summaryrefslogtreecommitdiffstats
path: root/js/src/jit/shared/LIR-shared.h
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/jit/shared/LIR-shared.h')
-rw-r--r--js/src/jit/shared/LIR-shared.h4272
1 files changed, 4272 insertions, 0 deletions
diff --git a/js/src/jit/shared/LIR-shared.h b/js/src/jit/shared/LIR-shared.h
new file mode 100644
index 0000000000..03b0ccef53
--- /dev/null
+++ b/js/src/jit/shared/LIR-shared.h
@@ -0,0 +1,4272 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: set ts=8 sts=2 et sw=2 tw=80:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef jit_shared_LIR_shared_h
+#define jit_shared_LIR_shared_h
+
+#include "mozilla/Maybe.h"
+#include "jit/AtomicOp.h"
+#include "jit/shared/Assembler-shared.h"
+#include "util/Memory.h"
+
+// This file declares LIR instructions that are common to every platform.
+
+namespace js {
+namespace jit {
+
+LIR_OPCODE_CLASS_GENERATED
+
+#ifdef FUZZING_JS_FUZZILLI
+class LFuzzilliHashT : public LInstructionHelper<1, 1, 2> {
+ public:
+ LIR_HEADER(FuzzilliHashT);
+
+ LFuzzilliHashT(const LAllocation& value, const LDefinition& temp,
+ const LDefinition& tempFloat)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, value);
+ setTemp(0, temp);
+ setTemp(1, tempFloat);
+ }
+
+ const LAllocation* value() { return getOperand(0); }
+
+ MFuzzilliHash* mir() const { return mir_->toFuzzilliHash(); }
+};
+
+class LFuzzilliHashV : public LInstructionHelper<1, BOX_PIECES, 2> {
+ public:
+ LIR_HEADER(FuzzilliHashV);
+
+ LFuzzilliHashV(const LBoxAllocation& value, const LDefinition& temp,
+ const LDefinition& tempFloat)
+ : LInstructionHelper(classOpcode) {
+ setBoxOperand(0, value);
+ setTemp(0, temp);
+ setTemp(1, tempFloat);
+ }
+
+ MFuzzilliHash* mir() const { return mir_->toFuzzilliHash(); }
+};
+
+class LFuzzilliHashStore : public LInstructionHelper<0, 1, 2> {
+ public:
+ LIR_HEADER(FuzzilliHashStore);
+
+ LFuzzilliHashStore(const LAllocation& value, const LDefinition& temp1,
+ const LDefinition& temp2)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, value);
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ }
+
+ const LAllocation* value() { return getOperand(0); }
+
+ MFuzzilliHashStore* mir() const { return mir_->toFuzzilliHashStore(); }
+};
+#endif
+
+class LBox : public LInstructionHelper<BOX_PIECES, 1, 0> {
+ MIRType type_;
+
+ public:
+ LIR_HEADER(Box);
+
+ LBox(const LAllocation& payload, MIRType type)
+ : LInstructionHelper(classOpcode), type_(type) {
+ setOperand(0, payload);
+ }
+
+ MIRType type() const { return type_; }
+ const char* extraName() const { return StringFromMIRType(type_); }
+};
+
+template <size_t Temps, size_t ExtraUses = 0>
+class LBinaryMath : public LInstructionHelper<1, 2 + ExtraUses, Temps> {
+ protected:
+ explicit LBinaryMath(LNode::Opcode opcode)
+ : LInstructionHelper<1, 2 + ExtraUses, Temps>(opcode) {}
+
+ public:
+ const LAllocation* lhs() { return this->getOperand(0); }
+ const LAllocation* rhs() { return this->getOperand(1); }
+};
+
+template <size_t Temps, size_t ExtraUses = 0>
+class LUnaryMath : public LInstructionHelper<1, 1 + ExtraUses, Temps> {
+ protected:
+ explicit LUnaryMath(LNode::Opcode opcode)
+ : LInstructionHelper<1, 1 + ExtraUses, Temps>(opcode) {}
+
+ public:
+ const LAllocation* input() { return this->getOperand(0); }
+};
+
+// An LOsiPoint captures a snapshot after a call and ensures enough space to
+// patch in a call to the invalidation mechanism.
+//
+// Note: LSafepoints are 1:1 with LOsiPoints, so it holds a reference to the
+// corresponding LSafepoint to inform it of the LOsiPoint's masm offset when it
+// gets GC'd.
+class LOsiPoint : public LInstructionHelper<0, 0, 0> {
+ LSafepoint* safepoint_;
+
+ public:
+ LOsiPoint(LSafepoint* safepoint, LSnapshot* snapshot)
+ : LInstructionHelper(classOpcode), safepoint_(safepoint) {
+ MOZ_ASSERT(safepoint && snapshot);
+ assignSnapshot(snapshot);
+ }
+
+ LSafepoint* associatedSafepoint() { return safepoint_; }
+
+ LIR_HEADER(OsiPoint)
+};
+
+class LMove {
+ LAllocation from_;
+ LAllocation to_;
+ LDefinition::Type type_;
+
+ public:
+ LMove(LAllocation from, LAllocation to, LDefinition::Type type)
+ : from_(from), to_(to), type_(type) {}
+
+ LAllocation from() const { return from_; }
+ LAllocation to() const { return to_; }
+ LDefinition::Type type() const { return type_; }
+};
+
+class LMoveGroup : public LInstructionHelper<0, 0, 0> {
+ js::Vector<LMove, 2, JitAllocPolicy> moves_;
+
+#ifdef JS_CODEGEN_X86
+ // Optional general register available for use when executing moves.
+ LAllocation scratchRegister_;
+#endif
+
+ explicit LMoveGroup(TempAllocator& alloc)
+ : LInstructionHelper(classOpcode), moves_(alloc) {}
+
+ public:
+ LIR_HEADER(MoveGroup)
+
+ static LMoveGroup* New(TempAllocator& alloc) {
+ return new (alloc) LMoveGroup(alloc);
+ }
+
+ void printOperands(GenericPrinter& out);
+
+ // Add a move which takes place simultaneously with all others in the group.
+ bool add(LAllocation from, LAllocation to, LDefinition::Type type);
+
+ // Add a move which takes place after existing moves in the group.
+ bool addAfter(LAllocation from, LAllocation to, LDefinition::Type type);
+
+ size_t numMoves() const { return moves_.length(); }
+ const LMove& getMove(size_t i) const { return moves_[i]; }
+
+#ifdef JS_CODEGEN_X86
+ void setScratchRegister(Register reg) { scratchRegister_ = LGeneralReg(reg); }
+ LAllocation maybeScratchRegister() { return scratchRegister_; }
+#endif
+
+ bool uses(Register reg) {
+ for (size_t i = 0; i < numMoves(); i++) {
+ LMove move = getMove(i);
+ if (move.from() == LGeneralReg(reg) || move.to() == LGeneralReg(reg)) {
+ return true;
+ }
+ }
+ return false;
+ }
+};
+
+// A constant Value.
+class LValue : public LInstructionHelper<BOX_PIECES, 0, 0> {
+ Value v_;
+
+ public:
+ LIR_HEADER(Value)
+
+ explicit LValue(const Value& v) : LInstructionHelper(classOpcode), v_(v) {}
+
+ Value value() const { return v_; }
+};
+
+// Base class for control instructions (goto, branch, etc.)
+template <size_t Succs, size_t Operands, size_t Temps>
+class LControlInstructionHelper
+ : public LInstructionHelper<0, Operands, Temps> {
+ mozilla::Array<MBasicBlock*, Succs> successors_;
+
+ protected:
+ explicit LControlInstructionHelper(LNode::Opcode opcode)
+ : LInstructionHelper<0, Operands, Temps>(opcode) {}
+
+ public:
+ size_t numSuccessors() const { return Succs; }
+ MBasicBlock* getSuccessor(size_t i) const { return successors_[i]; }
+
+ void setSuccessor(size_t i, MBasicBlock* successor) {
+ successors_[i] = successor;
+ }
+};
+
+// Jumps to the start of a basic block.
+class LGoto : public LControlInstructionHelper<1, 0, 0> {
+ public:
+ LIR_HEADER(Goto)
+
+ explicit LGoto(MBasicBlock* block) : LControlInstructionHelper(classOpcode) {
+ setSuccessor(0, block);
+ }
+
+ MBasicBlock* target() const { return getSuccessor(0); }
+};
+
+class LNewArray : public LInstructionHelper<1, 0, 1> {
+ public:
+ LIR_HEADER(NewArray)
+
+ explicit LNewArray(const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setTemp(0, temp);
+ }
+
+ const char* extraName() const {
+ return mir()->isVMCall() ? "VMCall" : nullptr;
+ }
+
+ const LDefinition* temp() { return getTemp(0); }
+
+ MNewArray* mir() const { return mir_->toNewArray(); }
+};
+
+class LNewObject : public LInstructionHelper<1, 0, 1> {
+ public:
+ LIR_HEADER(NewObject)
+
+ explicit LNewObject(const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setTemp(0, temp);
+ }
+
+ const char* extraName() const {
+ return mir()->isVMCall() ? "VMCall" : nullptr;
+ }
+
+ const LDefinition* temp() { return getTemp(0); }
+
+ MNewObject* mir() const { return mir_->toNewObject(); }
+};
+
+template <size_t Defs, size_t Ops>
+class LWasmReinterpretBase : public LInstructionHelper<Defs, Ops, 0> {
+ typedef LInstructionHelper<Defs, Ops, 0> Base;
+
+ protected:
+ explicit LWasmReinterpretBase(LNode::Opcode opcode) : Base(opcode) {}
+
+ public:
+ const LAllocation* input() { return Base::getOperand(0); }
+ MWasmReinterpret* mir() const { return Base::mir_->toWasmReinterpret(); }
+};
+
+class LWasmReinterpret : public LWasmReinterpretBase<1, 1> {
+ public:
+ LIR_HEADER(WasmReinterpret);
+ explicit LWasmReinterpret(const LAllocation& input)
+ : LWasmReinterpretBase(classOpcode) {
+ setOperand(0, input);
+ }
+};
+
+class LWasmReinterpretFromI64 : public LWasmReinterpretBase<1, INT64_PIECES> {
+ public:
+ static const size_t Input = 0;
+
+ LIR_HEADER(WasmReinterpretFromI64);
+ explicit LWasmReinterpretFromI64(const LInt64Allocation& input)
+ : LWasmReinterpretBase(classOpcode) {
+ setInt64Operand(Input, input);
+ }
+};
+
+class LWasmReinterpretToI64 : public LWasmReinterpretBase<INT64_PIECES, 1> {
+ public:
+ LIR_HEADER(WasmReinterpretToI64);
+ explicit LWasmReinterpretToI64(const LAllocation& input)
+ : LWasmReinterpretBase(classOpcode) {
+ setOperand(0, input);
+ }
+};
+
+namespace details {
+template <size_t Defs, size_t Ops, size_t Temps>
+class RotateBase : public LInstructionHelper<Defs, Ops, Temps> {
+ typedef LInstructionHelper<Defs, Ops, Temps> Base;
+
+ protected:
+ explicit RotateBase(LNode::Opcode opcode) : Base(opcode) {}
+
+ public:
+ MRotate* mir() { return Base::mir_->toRotate(); }
+};
+} // namespace details
+
+class LRotate : public details::RotateBase<1, 2, 0> {
+ public:
+ LIR_HEADER(Rotate);
+
+ LRotate() : RotateBase(classOpcode) {}
+
+ const LAllocation* input() { return getOperand(0); }
+ LAllocation* count() { return getOperand(1); }
+};
+
+class LRotateI64
+ : public details::RotateBase<INT64_PIECES, INT64_PIECES + 1, 1> {
+ public:
+ LIR_HEADER(RotateI64);
+
+ LRotateI64() : RotateBase(classOpcode) {
+ setTemp(0, LDefinition::BogusTemp());
+ }
+
+ static const size_t Input = 0;
+ static const size_t Count = INT64_PIECES;
+
+ const LInt64Allocation input() { return getInt64Operand(Input); }
+ const LDefinition* temp() { return getTemp(0); }
+ LAllocation* count() { return getOperand(Count); }
+};
+
+// Allocate a new arguments object for an inlined frame.
+class LCreateInlinedArgumentsObject : public LVariadicInstruction<1, 2> {
+ public:
+ LIR_HEADER(CreateInlinedArgumentsObject)
+
+ static const size_t CallObj = 0;
+ static const size_t Callee = 1;
+ static const size_t NumNonArgumentOperands = 2;
+ static size_t ArgIndex(size_t i) {
+ return NumNonArgumentOperands + BOX_PIECES * i;
+ }
+
+ LCreateInlinedArgumentsObject(uint32_t numOperands, const LDefinition& temp1,
+ const LDefinition& temp2)
+ : LVariadicInstruction(classOpcode, numOperands) {
+ setIsCall();
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ }
+
+ const LAllocation* getCallObject() { return getOperand(CallObj); }
+ const LAllocation* getCallee() { return getOperand(Callee); }
+
+ const LDefinition* temp1() { return getTemp(0); }
+ const LDefinition* temp2() { return getTemp(1); }
+
+ MCreateInlinedArgumentsObject* mir() const {
+ return mir_->toCreateInlinedArgumentsObject();
+ }
+};
+
+class LGetInlinedArgument : public LVariadicInstruction<BOX_PIECES, 0> {
+ public:
+ LIR_HEADER(GetInlinedArgument)
+
+ static const size_t Index = 0;
+ static const size_t NumNonArgumentOperands = 1;
+ static size_t ArgIndex(size_t i) {
+ return NumNonArgumentOperands + BOX_PIECES * i;
+ }
+
+ explicit LGetInlinedArgument(uint32_t numOperands)
+ : LVariadicInstruction(classOpcode, numOperands) {}
+
+ const LAllocation* getIndex() { return getOperand(Index); }
+
+ MGetInlinedArgument* mir() const { return mir_->toGetInlinedArgument(); }
+};
+
+class LGetInlinedArgumentHole : public LVariadicInstruction<BOX_PIECES, 0> {
+ public:
+ LIR_HEADER(GetInlinedArgumentHole)
+
+ static const size_t Index = 0;
+ static const size_t NumNonArgumentOperands = 1;
+ static size_t ArgIndex(size_t i) {
+ return NumNonArgumentOperands + BOX_PIECES * i;
+ }
+
+ explicit LGetInlinedArgumentHole(uint32_t numOperands)
+ : LVariadicInstruction(classOpcode, numOperands) {}
+
+ const LAllocation* getIndex() { return getOperand(Index); }
+
+ MGetInlinedArgumentHole* mir() const {
+ return mir_->toGetInlinedArgumentHole();
+ }
+};
+
+class LInlineArgumentsSlice : public LVariadicInstruction<1, 1> {
+ public:
+ LIR_HEADER(InlineArgumentsSlice)
+
+ static const size_t Begin = 0;
+ static const size_t Count = 1;
+ static const size_t NumNonArgumentOperands = 2;
+ static size_t ArgIndex(size_t i) {
+ return NumNonArgumentOperands + BOX_PIECES * i;
+ }
+
+ explicit LInlineArgumentsSlice(uint32_t numOperands, const LDefinition& temp)
+ : LVariadicInstruction(classOpcode, numOperands) {
+ setTemp(0, temp);
+ }
+
+ const LAllocation* begin() { return getOperand(Begin); }
+ const LAllocation* count() { return getOperand(Count); }
+ const LDefinition* temp() { return getTemp(0); }
+
+ MInlineArgumentsSlice* mir() const { return mir_->toInlineArgumentsSlice(); }
+};
+
+// Common code for LIR descended from MCall.
+template <size_t Defs, size_t Operands, size_t Temps>
+class LJSCallInstructionHelper
+ : public LCallInstructionHelper<Defs, Operands, Temps> {
+ protected:
+ explicit LJSCallInstructionHelper(LNode::Opcode opcode)
+ : LCallInstructionHelper<Defs, Operands, Temps>(opcode) {}
+
+ public:
+ MCall* mir() const { return this->mir_->toCall(); }
+
+ bool hasSingleTarget() const { return getSingleTarget() != nullptr; }
+ WrappedFunction* getSingleTarget() const { return mir()->getSingleTarget(); }
+
+ // Does not include |this|.
+ uint32_t numActualArgs() const { return mir()->numActualArgs(); }
+
+ bool isConstructing() const { return mir()->isConstructing(); }
+ bool ignoresReturnValue() const { return mir()->ignoresReturnValue(); }
+};
+
+// Generates a polymorphic callsite, wherein the function being called is
+// unknown and anticipated to vary.
+class LCallGeneric : public LJSCallInstructionHelper<BOX_PIECES, 1, 2> {
+ public:
+ LIR_HEADER(CallGeneric)
+
+ LCallGeneric(const LAllocation& func, const LDefinition& nargsreg,
+ const LDefinition& tmpobjreg)
+ : LJSCallInstructionHelper(classOpcode) {
+ setOperand(0, func);
+ setTemp(0, nargsreg);
+ setTemp(1, tmpobjreg);
+ }
+
+ const LAllocation* getFunction() { return getOperand(0); }
+ const LDefinition* getNargsReg() { return getTemp(0); }
+ const LDefinition* getTempObject() { return getTemp(1); }
+};
+
+// Generates a hardcoded callsite for a known, non-native target.
+class LCallKnown : public LJSCallInstructionHelper<BOX_PIECES, 1, 1> {
+ public:
+ LIR_HEADER(CallKnown)
+
+ LCallKnown(const LAllocation& func, const LDefinition& tmpobjreg)
+ : LJSCallInstructionHelper(classOpcode) {
+ setOperand(0, func);
+ setTemp(0, tmpobjreg);
+ }
+
+ const LAllocation* getFunction() { return getOperand(0); }
+ const LDefinition* getTempObject() { return getTemp(0); }
+};
+
+// Generates a hardcoded callsite for a known, native target.
+class LCallNative : public LJSCallInstructionHelper<BOX_PIECES, 0, 4> {
+ public:
+ LIR_HEADER(CallNative)
+
+ LCallNative(const LDefinition& argContext, const LDefinition& argUintN,
+ const LDefinition& argVp, const LDefinition& tmpreg)
+ : LJSCallInstructionHelper(classOpcode) {
+ // Registers used for callWithABI().
+ setTemp(0, argContext);
+ setTemp(1, argUintN);
+ setTemp(2, argVp);
+
+ // Temporary registers.
+ setTemp(3, tmpreg);
+ }
+
+ const LDefinition* getArgContextReg() { return getTemp(0); }
+ const LDefinition* getArgUintNReg() { return getTemp(1); }
+ const LDefinition* getArgVpReg() { return getTemp(2); }
+ const LDefinition* getTempReg() { return getTemp(3); }
+};
+
+class LCallClassHook : public LCallInstructionHelper<BOX_PIECES, 1, 4> {
+ public:
+ LIR_HEADER(CallClassHook)
+
+ LCallClassHook(const LAllocation& callee, const LDefinition& argContext,
+ const LDefinition& argUintN, const LDefinition& argVp,
+ const LDefinition& tmpreg)
+ : LCallInstructionHelper(classOpcode) {
+ setOperand(0, callee);
+
+ // Registers used for callWithABI().
+ setTemp(0, argContext);
+ setTemp(1, argUintN);
+ setTemp(2, argVp);
+
+ // Temporary registers.
+ setTemp(3, tmpreg);
+ }
+
+ MCallClassHook* mir() const { return mir_->toCallClassHook(); }
+
+ const LAllocation* getCallee() { return this->getOperand(0); }
+
+ const LDefinition* getArgContextReg() { return getTemp(0); }
+ const LDefinition* getArgUintNReg() { return getTemp(1); }
+ const LDefinition* getArgVpReg() { return getTemp(2); }
+ const LDefinition* getTempReg() { return getTemp(3); }
+};
+
+// Generates a hardcoded callsite for a known, DOM-native target.
+class LCallDOMNative : public LJSCallInstructionHelper<BOX_PIECES, 0, 4> {
+ public:
+ LIR_HEADER(CallDOMNative)
+
+ LCallDOMNative(const LDefinition& argJSContext, const LDefinition& argObj,
+ const LDefinition& argPrivate, const LDefinition& argArgs)
+ : LJSCallInstructionHelper(classOpcode) {
+ setTemp(0, argJSContext);
+ setTemp(1, argObj);
+ setTemp(2, argPrivate);
+ setTemp(3, argArgs);
+ }
+
+ const LDefinition* getArgJSContext() { return getTemp(0); }
+ const LDefinition* getArgObj() { return getTemp(1); }
+ const LDefinition* getArgPrivate() { return getTemp(2); }
+ const LDefinition* getArgArgs() { return getTemp(3); }
+};
+
+class LUnreachable : public LControlInstructionHelper<0, 0, 0> {
+ public:
+ LIR_HEADER(Unreachable)
+
+ LUnreachable() : LControlInstructionHelper(classOpcode) {}
+};
+
+class LUnreachableResultV : public LInstructionHelper<BOX_PIECES, 0, 0> {
+ public:
+ LIR_HEADER(UnreachableResultV)
+
+ LUnreachableResultV() : LInstructionHelper(classOpcode) {}
+};
+
+template <size_t defs, size_t ops>
+class LDOMPropertyInstructionHelper
+ : public LCallInstructionHelper<defs, 1 + ops, 3> {
+ protected:
+ LDOMPropertyInstructionHelper(LNode::Opcode opcode,
+ const LDefinition& JSContextReg,
+ const LAllocation& ObjectReg,
+ const LDefinition& PrivReg,
+ const LDefinition& ValueReg)
+ : LCallInstructionHelper<defs, 1 + ops, 3>(opcode) {
+ this->setOperand(0, ObjectReg);
+ this->setTemp(0, JSContextReg);
+ this->setTemp(1, PrivReg);
+ this->setTemp(2, ValueReg);
+ }
+
+ public:
+ const LDefinition* getJSContextReg() { return this->getTemp(0); }
+ const LAllocation* getObjectReg() { return this->getOperand(0); }
+ const LDefinition* getPrivReg() { return this->getTemp(1); }
+ const LDefinition* getValueReg() { return this->getTemp(2); }
+};
+
+class LGetDOMProperty : public LDOMPropertyInstructionHelper<BOX_PIECES, 0> {
+ public:
+ LIR_HEADER(GetDOMProperty)
+
+ LGetDOMProperty(const LDefinition& JSContextReg, const LAllocation& ObjectReg,
+ const LDefinition& PrivReg, const LDefinition& ValueReg)
+ : LDOMPropertyInstructionHelper<BOX_PIECES, 0>(
+ classOpcode, JSContextReg, ObjectReg, PrivReg, ValueReg) {}
+
+ MGetDOMProperty* mir() const { return mir_->toGetDOMProperty(); }
+};
+
+class LGetDOMMemberV : public LInstructionHelper<BOX_PIECES, 1, 0> {
+ public:
+ LIR_HEADER(GetDOMMemberV);
+ explicit LGetDOMMemberV(const LAllocation& object)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, object);
+ }
+
+ const LAllocation* object() { return getOperand(0); }
+
+ MGetDOMMember* mir() const { return mir_->toGetDOMMember(); }
+};
+
+class LSetDOMProperty : public LDOMPropertyInstructionHelper<0, BOX_PIECES> {
+ public:
+ LIR_HEADER(SetDOMProperty)
+
+ LSetDOMProperty(const LDefinition& JSContextReg, const LAllocation& ObjectReg,
+ const LBoxAllocation& value, const LDefinition& PrivReg,
+ const LDefinition& ValueReg)
+ : LDOMPropertyInstructionHelper<0, BOX_PIECES>(
+ classOpcode, JSContextReg, ObjectReg, PrivReg, ValueReg) {
+ setBoxOperand(Value, value);
+ }
+
+ static const size_t Value = 1;
+
+ MSetDOMProperty* mir() const { return mir_->toSetDOMProperty(); }
+};
+
+// Generates a polymorphic callsite, wherein the function being called is
+// unknown and anticipated to vary.
+class LApplyArgsGeneric
+ : public LCallInstructionHelper<BOX_PIECES, BOX_PIECES + 2, 2> {
+ public:
+ LIR_HEADER(ApplyArgsGeneric)
+
+ LApplyArgsGeneric(const LAllocation& func, const LAllocation& argc,
+ const LBoxAllocation& thisv, const LDefinition& tmpobjreg,
+ const LDefinition& tmpcopy)
+ : LCallInstructionHelper(classOpcode) {
+ setOperand(0, func);
+ setOperand(1, argc);
+ setBoxOperand(ThisIndex, thisv);
+ setTemp(0, tmpobjreg);
+ setTemp(1, tmpcopy);
+ }
+
+ MApplyArgs* mir() const { return mir_->toApplyArgs(); }
+
+ bool hasSingleTarget() const { return getSingleTarget() != nullptr; }
+ WrappedFunction* getSingleTarget() const { return mir()->getSingleTarget(); }
+
+ uint32_t numExtraFormals() const { return mir()->numExtraFormals(); }
+
+ const LAllocation* getFunction() { return getOperand(0); }
+ const LAllocation* getArgc() { return getOperand(1); }
+ static const size_t ThisIndex = 2;
+
+ const LDefinition* getTempObject() { return getTemp(0); }
+ const LDefinition* getTempForArgCopy() { return getTemp(1); }
+};
+
+class LApplyArgsObj
+ : public LCallInstructionHelper<BOX_PIECES, BOX_PIECES + 2, 2> {
+ public:
+ LIR_HEADER(ApplyArgsObj)
+
+ LApplyArgsObj(const LAllocation& func, const LAllocation& argsObj,
+ const LBoxAllocation& thisv, const LDefinition& tmpObjReg,
+ const LDefinition& tmpCopy)
+ : LCallInstructionHelper(classOpcode) {
+ setOperand(0, func);
+ setOperand(1, argsObj);
+ setBoxOperand(ThisIndex, thisv);
+ setTemp(0, tmpObjReg);
+ setTemp(1, tmpCopy);
+ }
+
+ MApplyArgsObj* mir() const { return mir_->toApplyArgsObj(); }
+
+ bool hasSingleTarget() const { return getSingleTarget() != nullptr; }
+ WrappedFunction* getSingleTarget() const { return mir()->getSingleTarget(); }
+
+ const LAllocation* getFunction() { return getOperand(0); }
+ const LAllocation* getArgsObj() { return getOperand(1); }
+ // All registers are calltemps. argc is mapped to the same register as
+ // ArgsObj. argc becomes live as ArgsObj is dying.
+ const LAllocation* getArgc() { return getOperand(1); }
+ static const size_t ThisIndex = 2;
+
+ const LDefinition* getTempObject() { return getTemp(0); }
+ const LDefinition* getTempForArgCopy() { return getTemp(1); }
+};
+
+class LApplyArrayGeneric
+ : public LCallInstructionHelper<BOX_PIECES, BOX_PIECES + 2, 2> {
+ public:
+ LIR_HEADER(ApplyArrayGeneric)
+
+ LApplyArrayGeneric(const LAllocation& func, const LAllocation& elements,
+ const LBoxAllocation& thisv, const LDefinition& tmpobjreg,
+ const LDefinition& tmpcopy)
+ : LCallInstructionHelper(classOpcode) {
+ setOperand(0, func);
+ setOperand(1, elements);
+ setBoxOperand(ThisIndex, thisv);
+ setTemp(0, tmpobjreg);
+ setTemp(1, tmpcopy);
+ }
+
+ MApplyArray* mir() const { return mir_->toApplyArray(); }
+
+ bool hasSingleTarget() const { return getSingleTarget() != nullptr; }
+ WrappedFunction* getSingleTarget() const { return mir()->getSingleTarget(); }
+
+ const LAllocation* getFunction() { return getOperand(0); }
+ const LAllocation* getElements() { return getOperand(1); }
+ // argc is mapped to the same register as elements: argc becomes
+ // live as elements is dying, all registers are calltemps.
+ const LAllocation* getArgc() { return getOperand(1); }
+ static const size_t ThisIndex = 2;
+
+ const LDefinition* getTempObject() { return getTemp(0); }
+ const LDefinition* getTempForArgCopy() { return getTemp(1); }
+};
+
+class LConstructArgsGeneric
+ : public LCallInstructionHelper<BOX_PIECES, BOX_PIECES + 3, 1> {
+ public:
+ LIR_HEADER(ConstructArgsGeneric)
+
+ LConstructArgsGeneric(const LAllocation& func, const LAllocation& argc,
+ const LAllocation& newTarget,
+ const LBoxAllocation& thisv,
+ const LDefinition& tmpobjreg)
+ : LCallInstructionHelper(classOpcode) {
+ setOperand(0, func);
+ setOperand(1, argc);
+ setOperand(2, newTarget);
+ setBoxOperand(ThisIndex, thisv);
+ setTemp(0, tmpobjreg);
+ }
+
+ MConstructArgs* mir() const { return mir_->toConstructArgs(); }
+
+ bool hasSingleTarget() const { return getSingleTarget() != nullptr; }
+ WrappedFunction* getSingleTarget() const { return mir()->getSingleTarget(); }
+
+ uint32_t numExtraFormals() const { return mir()->numExtraFormals(); }
+
+ const LAllocation* getFunction() { return getOperand(0); }
+ const LAllocation* getArgc() { return getOperand(1); }
+ const LAllocation* getNewTarget() { return getOperand(2); }
+
+ static const size_t ThisIndex = 3;
+
+ const LDefinition* getTempObject() { return getTemp(0); }
+
+ // tempForArgCopy is mapped to the same register as newTarget:
+ // tempForArgCopy becomes live as newTarget is dying, all registers are
+ // calltemps.
+ const LAllocation* getTempForArgCopy() { return getOperand(2); }
+};
+
+class LConstructArrayGeneric
+ : public LCallInstructionHelper<BOX_PIECES, BOX_PIECES + 3, 1> {
+ public:
+ LIR_HEADER(ConstructArrayGeneric)
+
+ LConstructArrayGeneric(const LAllocation& func, const LAllocation& elements,
+ const LAllocation& newTarget,
+ const LBoxAllocation& thisv,
+ const LDefinition& tmpobjreg)
+ : LCallInstructionHelper(classOpcode) {
+ setOperand(0, func);
+ setOperand(1, elements);
+ setOperand(2, newTarget);
+ setBoxOperand(ThisIndex, thisv);
+ setTemp(0, tmpobjreg);
+ }
+
+ MConstructArray* mir() const { return mir_->toConstructArray(); }
+
+ bool hasSingleTarget() const { return getSingleTarget() != nullptr; }
+ WrappedFunction* getSingleTarget() const { return mir()->getSingleTarget(); }
+
+ const LAllocation* getFunction() { return getOperand(0); }
+ const LAllocation* getElements() { return getOperand(1); }
+ const LAllocation* getNewTarget() { return getOperand(2); }
+
+ static const size_t ThisIndex = 3;
+
+ const LDefinition* getTempObject() { return getTemp(0); }
+
+ // argc is mapped to the same register as elements: argc becomes
+ // live as elements is dying, all registers are calltemps.
+ const LAllocation* getArgc() { return getOperand(1); }
+
+ // tempForArgCopy is mapped to the same register as newTarget:
+ // tempForArgCopy becomes live as newTarget is dying, all registers are
+ // calltemps.
+ const LAllocation* getTempForArgCopy() { return getOperand(2); }
+};
+
+// Takes in either an integer or boolean input and tests it for truthiness.
+class LTestIAndBranch : public LControlInstructionHelper<2, 1, 0> {
+ public:
+ LIR_HEADER(TestIAndBranch)
+
+ LTestIAndBranch(const LAllocation& in, MBasicBlock* ifTrue,
+ MBasicBlock* ifFalse)
+ : LControlInstructionHelper(classOpcode) {
+ setOperand(0, in);
+ setSuccessor(0, ifTrue);
+ setSuccessor(1, ifFalse);
+ }
+
+ MBasicBlock* ifTrue() const { return getSuccessor(0); }
+ MBasicBlock* ifFalse() const { return getSuccessor(1); }
+};
+
+// Takes in an int64 input and tests it for truthiness.
+class LTestI64AndBranch : public LControlInstructionHelper<2, INT64_PIECES, 0> {
+ public:
+ LIR_HEADER(TestI64AndBranch)
+
+ LTestI64AndBranch(const LInt64Allocation& in, MBasicBlock* ifTrue,
+ MBasicBlock* ifFalse)
+ : LControlInstructionHelper(classOpcode) {
+ setInt64Operand(0, in);
+ setSuccessor(0, ifTrue);
+ setSuccessor(1, ifFalse);
+ }
+
+ MBasicBlock* ifTrue() const { return getSuccessor(0); }
+ MBasicBlock* ifFalse() const { return getSuccessor(1); }
+};
+
+// Takes in a double input and tests it for truthiness.
+class LTestDAndBranch : public LControlInstructionHelper<2, 1, 0> {
+ public:
+ LIR_HEADER(TestDAndBranch)
+
+ LTestDAndBranch(const LAllocation& in, MBasicBlock* ifTrue,
+ MBasicBlock* ifFalse)
+ : LControlInstructionHelper(classOpcode) {
+ setOperand(0, in);
+ setSuccessor(0, ifTrue);
+ setSuccessor(1, ifFalse);
+ }
+
+ MBasicBlock* ifTrue() const { return getSuccessor(0); }
+ MBasicBlock* ifFalse() const { return getSuccessor(1); }
+};
+
+// Takes in a float32 input and tests it for truthiness.
+class LTestFAndBranch : public LControlInstructionHelper<2, 1, 0> {
+ public:
+ LIR_HEADER(TestFAndBranch)
+
+ LTestFAndBranch(const LAllocation& in, MBasicBlock* ifTrue,
+ MBasicBlock* ifFalse)
+ : LControlInstructionHelper(classOpcode) {
+ setOperand(0, in);
+ setSuccessor(0, ifTrue);
+ setSuccessor(1, ifFalse);
+ }
+
+ MBasicBlock* ifTrue() const { return getSuccessor(0); }
+ MBasicBlock* ifFalse() const { return getSuccessor(1); }
+};
+
+// Takes in a bigint input and tests it for truthiness.
+class LTestBIAndBranch : public LControlInstructionHelper<2, 1, 0> {
+ public:
+ LIR_HEADER(TestBIAndBranch)
+
+ LTestBIAndBranch(const LAllocation& in, MBasicBlock* ifTrue,
+ MBasicBlock* ifFalse)
+ : LControlInstructionHelper(classOpcode) {
+ setOperand(0, in);
+ setSuccessor(0, ifTrue);
+ setSuccessor(1, ifFalse);
+ }
+
+ MBasicBlock* ifTrue() { return getSuccessor(0); }
+ MBasicBlock* ifFalse() { return getSuccessor(1); }
+};
+
+// Takes an object and tests it for truthiness. An object is falsy iff it
+// emulates |undefined|; see js::EmulatesUndefined.
+class LTestOAndBranch : public LControlInstructionHelper<2, 1, 1> {
+ public:
+ LIR_HEADER(TestOAndBranch)
+
+ LTestOAndBranch(const LAllocation& input, MBasicBlock* ifTruthy,
+ MBasicBlock* ifFalsy, const LDefinition& temp)
+ : LControlInstructionHelper(classOpcode) {
+ setOperand(0, input);
+ setSuccessor(0, ifTruthy);
+ setSuccessor(1, ifFalsy);
+ setTemp(0, temp);
+ }
+
+ const LDefinition* temp() { return getTemp(0); }
+
+ MBasicBlock* ifTruthy() { return getSuccessor(0); }
+ MBasicBlock* ifFalsy() { return getSuccessor(1); }
+
+ MTest* mir() { return mir_->toTest(); }
+};
+
+// Takes in a boxed value and tests it for truthiness.
+class LTestVAndBranch : public LControlInstructionHelper<2, BOX_PIECES, 3> {
+ public:
+ LIR_HEADER(TestVAndBranch)
+
+ LTestVAndBranch(MBasicBlock* ifTruthy, MBasicBlock* ifFalsy,
+ const LBoxAllocation& input, const LDefinition& temp0,
+ const LDefinition& temp1, const LDefinition& temp2)
+ : LControlInstructionHelper(classOpcode) {
+ setSuccessor(0, ifTruthy);
+ setSuccessor(1, ifFalsy);
+ setBoxOperand(Input, input);
+ setTemp(0, temp0);
+ setTemp(1, temp1);
+ setTemp(2, temp2);
+ }
+
+ static const size_t Input = 0;
+
+ const LDefinition* tempFloat() { return getTemp(0); }
+
+ const LDefinition* temp1() { return getTemp(1); }
+
+ const LDefinition* temp2() { return getTemp(2); }
+
+ MBasicBlock* ifTruthy() { return getSuccessor(0); }
+ MBasicBlock* ifFalsy() { return getSuccessor(1); }
+
+ MTest* mir() const { return mir_->toTest(); }
+};
+
+// Compares two integral values of the same JS type, either integer or object.
+// For objects, both operands are in registers.
+class LCompare : public LInstructionHelper<1, 2, 0> {
+ JSOp jsop_;
+
+ public:
+ LIR_HEADER(Compare)
+ LCompare(JSOp jsop, const LAllocation& left, const LAllocation& right)
+ : LInstructionHelper(classOpcode), jsop_(jsop) {
+ setOperand(0, left);
+ setOperand(1, right);
+ }
+
+ JSOp jsop() const { return jsop_; }
+ const LAllocation* left() { return getOperand(0); }
+ const LAllocation* right() { return getOperand(1); }
+ MCompare* mir() { return mir_->toCompare(); }
+ const char* extraName() const { return CodeName(jsop_); }
+};
+
+class LCompareI64 : public LInstructionHelper<1, 2 * INT64_PIECES, 0> {
+ JSOp jsop_;
+
+ public:
+ LIR_HEADER(CompareI64)
+
+ static const size_t Lhs = 0;
+ static const size_t Rhs = INT64_PIECES;
+
+ LCompareI64(JSOp jsop, const LInt64Allocation& left,
+ const LInt64Allocation& right)
+ : LInstructionHelper(classOpcode), jsop_(jsop) {
+ setInt64Operand(Lhs, left);
+ setInt64Operand(Rhs, right);
+ }
+
+ JSOp jsop() const { return jsop_; }
+ MCompare* mir() { return mir_->toCompare(); }
+ const char* extraName() const { return CodeName(jsop_); }
+};
+
+class LCompareI64AndBranch
+ : public LControlInstructionHelper<2, 2 * INT64_PIECES, 0> {
+ MCompare* cmpMir_;
+ JSOp jsop_;
+
+ public:
+ LIR_HEADER(CompareI64AndBranch)
+
+ static const size_t Lhs = 0;
+ static const size_t Rhs = INT64_PIECES;
+
+ LCompareI64AndBranch(MCompare* cmpMir, JSOp jsop,
+ const LInt64Allocation& left,
+ const LInt64Allocation& right, MBasicBlock* ifTrue,
+ MBasicBlock* ifFalse)
+ : LControlInstructionHelper(classOpcode), cmpMir_(cmpMir), jsop_(jsop) {
+ setInt64Operand(Lhs, left);
+ setInt64Operand(Rhs, right);
+ setSuccessor(0, ifTrue);
+ setSuccessor(1, ifFalse);
+ }
+
+ JSOp jsop() const { return jsop_; }
+ MBasicBlock* ifTrue() const { return getSuccessor(0); }
+ MBasicBlock* ifFalse() const { return getSuccessor(1); }
+ MTest* mir() const { return mir_->toTest(); }
+ MCompare* cmpMir() const { return cmpMir_; }
+ const char* extraName() const { return CodeName(jsop_); }
+};
+
+// Compares two integral values of the same JS type, either integer or object.
+// For objects, both operands are in registers.
+class LCompareAndBranch : public LControlInstructionHelper<2, 2, 0> {
+ MCompare* cmpMir_;
+ JSOp jsop_;
+
+ public:
+ LIR_HEADER(CompareAndBranch)
+ LCompareAndBranch(MCompare* cmpMir, JSOp jsop, const LAllocation& left,
+ const LAllocation& right, MBasicBlock* ifTrue,
+ MBasicBlock* ifFalse)
+ : LControlInstructionHelper(classOpcode), cmpMir_(cmpMir), jsop_(jsop) {
+ setOperand(0, left);
+ setOperand(1, right);
+ setSuccessor(0, ifTrue);
+ setSuccessor(1, ifFalse);
+ }
+
+ JSOp jsop() const { return jsop_; }
+ MBasicBlock* ifTrue() const { return getSuccessor(0); }
+ MBasicBlock* ifFalse() const { return getSuccessor(1); }
+ const LAllocation* left() { return getOperand(0); }
+ const LAllocation* right() { return getOperand(1); }
+ MTest* mir() const { return mir_->toTest(); }
+ MCompare* cmpMir() const { return cmpMir_; }
+ const char* extraName() const { return CodeName(jsop_); }
+};
+
+class LCompareDAndBranch : public LControlInstructionHelper<2, 2, 0> {
+ MCompare* cmpMir_;
+
+ public:
+ LIR_HEADER(CompareDAndBranch)
+
+ LCompareDAndBranch(MCompare* cmpMir, const LAllocation& left,
+ const LAllocation& right, MBasicBlock* ifTrue,
+ MBasicBlock* ifFalse)
+ : LControlInstructionHelper(classOpcode), cmpMir_(cmpMir) {
+ setOperand(0, left);
+ setOperand(1, right);
+ setSuccessor(0, ifTrue);
+ setSuccessor(1, ifFalse);
+ }
+
+ MBasicBlock* ifTrue() const { return getSuccessor(0); }
+ MBasicBlock* ifFalse() const { return getSuccessor(1); }
+ const LAllocation* left() { return getOperand(0); }
+ const LAllocation* right() { return getOperand(1); }
+ MTest* mir() const { return mir_->toTest(); }
+ MCompare* cmpMir() const { return cmpMir_; }
+};
+
+class LCompareFAndBranch : public LControlInstructionHelper<2, 2, 0> {
+ MCompare* cmpMir_;
+
+ public:
+ LIR_HEADER(CompareFAndBranch)
+ LCompareFAndBranch(MCompare* cmpMir, const LAllocation& left,
+ const LAllocation& right, MBasicBlock* ifTrue,
+ MBasicBlock* ifFalse)
+ : LControlInstructionHelper(classOpcode), cmpMir_(cmpMir) {
+ setOperand(0, left);
+ setOperand(1, right);
+ setSuccessor(0, ifTrue);
+ setSuccessor(1, ifFalse);
+ }
+
+ MBasicBlock* ifTrue() const { return getSuccessor(0); }
+ MBasicBlock* ifFalse() const { return getSuccessor(1); }
+ const LAllocation* left() { return getOperand(0); }
+ const LAllocation* right() { return getOperand(1); }
+ MTest* mir() const { return mir_->toTest(); }
+ MCompare* cmpMir() const { return cmpMir_; }
+};
+
+class LBitAndAndBranch : public LControlInstructionHelper<2, 2, 0> {
+ // This denotes only a single-word AND on the target. Hence `is64_` is
+ // required to be `false` on a 32-bit target.
+ bool is64_;
+ Assembler::Condition cond_;
+
+ public:
+ LIR_HEADER(BitAndAndBranch)
+ LBitAndAndBranch(MBasicBlock* ifTrue, MBasicBlock* ifFalse, bool is64,
+ Assembler::Condition cond = Assembler::NonZero)
+ : LControlInstructionHelper(classOpcode), is64_(is64), cond_(cond) {
+ setSuccessor(0, ifTrue);
+ setSuccessor(1, ifFalse);
+ }
+
+ MBasicBlock* ifTrue() const { return getSuccessor(0); }
+ MBasicBlock* ifFalse() const { return getSuccessor(1); }
+ const LAllocation* left() { return getOperand(0); }
+ const LAllocation* right() { return getOperand(1); }
+ bool is64() const { return is64_; }
+ Assembler::Condition cond() const {
+ MOZ_ASSERT(cond_ == Assembler::Zero || cond_ == Assembler::NonZero);
+ return cond_;
+ }
+};
+
+class LIsNullOrLikeUndefinedAndBranchV
+ : public LControlInstructionHelper<2, BOX_PIECES, 2> {
+ MCompare* cmpMir_;
+
+ public:
+ LIR_HEADER(IsNullOrLikeUndefinedAndBranchV)
+
+ LIsNullOrLikeUndefinedAndBranchV(MCompare* cmpMir, MBasicBlock* ifTrue,
+ MBasicBlock* ifFalse,
+ const LBoxAllocation& value,
+ const LDefinition& temp,
+ const LDefinition& tempToUnbox)
+ : LControlInstructionHelper(classOpcode), cmpMir_(cmpMir) {
+ setSuccessor(0, ifTrue);
+ setSuccessor(1, ifFalse);
+ setBoxOperand(Value, value);
+ setTemp(0, temp);
+ setTemp(1, tempToUnbox);
+ }
+
+ static const size_t Value = 0;
+
+ MBasicBlock* ifTrue() const { return getSuccessor(0); }
+ MBasicBlock* ifFalse() const { return getSuccessor(1); }
+ MTest* mir() const { return mir_->toTest(); }
+ MCompare* cmpMir() const { return cmpMir_; }
+ const LDefinition* temp() { return getTemp(0); }
+ const LDefinition* tempToUnbox() { return getTemp(1); }
+};
+
+class LIsNullOrLikeUndefinedAndBranchT
+ : public LControlInstructionHelper<2, 1, 1> {
+ MCompare* cmpMir_;
+
+ public:
+ LIR_HEADER(IsNullOrLikeUndefinedAndBranchT)
+
+ LIsNullOrLikeUndefinedAndBranchT(MCompare* cmpMir, const LAllocation& input,
+ MBasicBlock* ifTrue, MBasicBlock* ifFalse,
+ const LDefinition& temp)
+ : LControlInstructionHelper(classOpcode), cmpMir_(cmpMir) {
+ setOperand(0, input);
+ setSuccessor(0, ifTrue);
+ setSuccessor(1, ifFalse);
+ setTemp(0, temp);
+ }
+
+ MBasicBlock* ifTrue() const { return getSuccessor(0); }
+ MBasicBlock* ifFalse() const { return getSuccessor(1); }
+ MTest* mir() const { return mir_->toTest(); }
+ MCompare* cmpMir() const { return cmpMir_; }
+ const LDefinition* temp() { return getTemp(0); }
+};
+
+class LIsNullAndBranch : public LControlInstructionHelper<2, BOX_PIECES, 0> {
+ MCompare* cmpMir_;
+
+ public:
+ LIR_HEADER(IsNullAndBranch)
+
+ LIsNullAndBranch(MCompare* cmpMir, MBasicBlock* ifTrue, MBasicBlock* ifFalse,
+ const LBoxAllocation& value)
+ : LControlInstructionHelper(classOpcode), cmpMir_(cmpMir) {
+ setSuccessor(0, ifTrue);
+ setSuccessor(1, ifFalse);
+ setBoxOperand(Value, value);
+ }
+
+ static const size_t Value = 0;
+
+ MBasicBlock* ifTrue() const { return getSuccessor(0); }
+ MBasicBlock* ifFalse() const { return getSuccessor(1); }
+ MTest* mir() const { return mir_->toTest(); }
+ MCompare* cmpMir() const { return cmpMir_; }
+};
+
+class LIsUndefinedAndBranch
+ : public LControlInstructionHelper<2, BOX_PIECES, 0> {
+ MCompare* cmpMir_;
+
+ public:
+ LIR_HEADER(IsUndefinedAndBranch)
+
+ LIsUndefinedAndBranch(MCompare* cmpMir, MBasicBlock* ifTrue,
+ MBasicBlock* ifFalse, const LBoxAllocation& value)
+ : LControlInstructionHelper(classOpcode), cmpMir_(cmpMir) {
+ setSuccessor(0, ifTrue);
+ setSuccessor(1, ifFalse);
+ setBoxOperand(Value, value);
+ }
+
+ static const size_t Value = 0;
+
+ MBasicBlock* ifTrue() const { return getSuccessor(0); }
+ MBasicBlock* ifFalse() const { return getSuccessor(1); }
+ MTest* mir() const { return mir_->toTest(); }
+ MCompare* cmpMir() const { return cmpMir_; }
+};
+
+// Bitwise not operation, takes a 32-bit integer as input and returning
+// a 32-bit integer result as an output.
+class LBitNotI : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(BitNotI)
+
+ LBitNotI() : LInstructionHelper(classOpcode) {}
+};
+
+class LBitNotI64 : public LInstructionHelper<INT64_PIECES, INT64_PIECES, 0> {
+ public:
+ LIR_HEADER(BitNotI64)
+
+ LBitNotI64() : LInstructionHelper(classOpcode) {}
+};
+
+// Binary bitwise operation, taking two 32-bit integers as inputs and returning
+// a 32-bit integer result as an output.
+class LBitOpI : public LInstructionHelper<1, 2, 0> {
+ JSOp op_;
+
+ public:
+ LIR_HEADER(BitOpI)
+
+ explicit LBitOpI(JSOp op) : LInstructionHelper(classOpcode), op_(op) {}
+
+ const char* extraName() const {
+ if (bitop() == JSOp::Ursh && mir_->toUrsh()->bailoutsDisabled()) {
+ return "ursh:BailoutsDisabled";
+ }
+ return CodeName(op_);
+ }
+
+ JSOp bitop() const { return op_; }
+};
+
+class LBitOpI64 : public LInstructionHelper<INT64_PIECES, 2 * INT64_PIECES, 0> {
+ JSOp op_;
+
+ public:
+ LIR_HEADER(BitOpI64)
+
+ static const size_t Lhs = 0;
+ static const size_t Rhs = INT64_PIECES;
+
+ explicit LBitOpI64(JSOp op) : LInstructionHelper(classOpcode), op_(op) {}
+
+ const char* extraName() const { return CodeName(op_); }
+
+ JSOp bitop() const { return op_; }
+};
+
+// Shift operation, taking two 32-bit integers as inputs and returning
+// a 32-bit integer result as an output.
+class LShiftI : public LBinaryMath<0> {
+ JSOp op_;
+
+ public:
+ LIR_HEADER(ShiftI)
+
+ explicit LShiftI(JSOp op) : LBinaryMath(classOpcode), op_(op) {}
+
+ JSOp bitop() { return op_; }
+
+ MInstruction* mir() { return mir_->toInstruction(); }
+
+ const char* extraName() const { return CodeName(op_); }
+};
+
+class LShiftI64 : public LInstructionHelper<INT64_PIECES, INT64_PIECES + 1, 0> {
+ JSOp op_;
+
+ public:
+ LIR_HEADER(ShiftI64)
+
+ explicit LShiftI64(JSOp op) : LInstructionHelper(classOpcode), op_(op) {}
+
+ static const size_t Lhs = 0;
+ static const size_t Rhs = INT64_PIECES;
+
+ JSOp bitop() { return op_; }
+
+ MInstruction* mir() { return mir_->toInstruction(); }
+
+ const char* extraName() const { return CodeName(op_); }
+};
+
+class LSignExtendInt64
+ : public LInstructionHelper<INT64_PIECES, INT64_PIECES, 0> {
+ public:
+ LIR_HEADER(SignExtendInt64)
+
+ explicit LSignExtendInt64(const LInt64Allocation& input)
+ : LInstructionHelper(classOpcode) {
+ setInt64Operand(0, input);
+ }
+
+ const MSignExtendInt64* mir() const { return mir_->toSignExtendInt64(); }
+
+ MSignExtendInt64::Mode mode() const { return mir()->mode(); }
+};
+
+class LUrshD : public LBinaryMath<1> {
+ public:
+ LIR_HEADER(UrshD)
+
+ LUrshD(const LAllocation& lhs, const LAllocation& rhs,
+ const LDefinition& temp)
+ : LBinaryMath(classOpcode) {
+ setOperand(0, lhs);
+ setOperand(1, rhs);
+ setTemp(0, temp);
+ }
+ const LDefinition* temp() { return getTemp(0); }
+};
+
+// Returns from the function being compiled (not used in inlined frames). The
+// input must be a box.
+class LReturn : public LInstructionHelper<0, BOX_PIECES, 0> {
+ bool isGenerator_;
+
+ public:
+ LIR_HEADER(Return)
+
+ explicit LReturn(bool isGenerator)
+ : LInstructionHelper(classOpcode), isGenerator_(isGenerator) {}
+
+ bool isGenerator() { return isGenerator_; }
+};
+
+class LMinMaxBase : public LInstructionHelper<1, 2, 0> {
+ protected:
+ LMinMaxBase(LNode::Opcode opcode, const LAllocation& first,
+ const LAllocation& second)
+ : LInstructionHelper(opcode) {
+ setOperand(0, first);
+ setOperand(1, second);
+ }
+
+ public:
+ const LAllocation* first() { return this->getOperand(0); }
+ const LAllocation* second() { return this->getOperand(1); }
+ const LDefinition* output() { return this->getDef(0); }
+ MMinMax* mir() const { return mir_->toMinMax(); }
+ const char* extraName() const { return mir()->isMax() ? "Max" : "Min"; }
+};
+
+class LMinMaxI : public LMinMaxBase {
+ public:
+ LIR_HEADER(MinMaxI)
+ LMinMaxI(const LAllocation& first, const LAllocation& second)
+ : LMinMaxBase(classOpcode, first, second) {}
+};
+
+class LMinMaxD : public LMinMaxBase {
+ public:
+ LIR_HEADER(MinMaxD)
+ LMinMaxD(const LAllocation& first, const LAllocation& second)
+ : LMinMaxBase(classOpcode, first, second) {}
+};
+
+class LMinMaxF : public LMinMaxBase {
+ public:
+ LIR_HEADER(MinMaxF)
+ LMinMaxF(const LAllocation& first, const LAllocation& second)
+ : LMinMaxBase(classOpcode, first, second) {}
+};
+
+class LMinMaxArrayI : public LInstructionHelper<1, 1, 3> {
+ public:
+ LIR_HEADER(MinMaxArrayI);
+ LMinMaxArrayI(const LAllocation& array, const LDefinition& temp0,
+ const LDefinition& temp1, const LDefinition& temp2)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, array);
+ setTemp(0, temp0);
+ setTemp(1, temp1);
+ setTemp(2, temp2);
+ }
+
+ const LAllocation* array() { return getOperand(0); }
+ const LDefinition* temp1() { return getTemp(0); }
+ const LDefinition* temp2() { return getTemp(1); }
+ const LDefinition* temp3() { return getTemp(2); }
+
+ bool isMax() const { return mir_->toMinMaxArray()->isMax(); }
+};
+
+class LMinMaxArrayD : public LInstructionHelper<1, 1, 3> {
+ public:
+ LIR_HEADER(MinMaxArrayD);
+ LMinMaxArrayD(const LAllocation& array, const LDefinition& floatTemp,
+ const LDefinition& temp1, const LDefinition& temp2)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, array);
+ setTemp(0, floatTemp);
+ setTemp(1, temp1);
+ setTemp(2, temp2);
+ }
+
+ const LAllocation* array() { return getOperand(0); }
+ const LDefinition* floatTemp() { return getTemp(0); }
+ const LDefinition* temp1() { return getTemp(1); }
+ const LDefinition* temp2() { return getTemp(2); }
+
+ bool isMax() const { return mir_->toMinMaxArray()->isMax(); }
+};
+
+// Copysign for doubles.
+class LCopySignD : public LInstructionHelper<1, 2, 2> {
+ public:
+ LIR_HEADER(CopySignD)
+ explicit LCopySignD() : LInstructionHelper(classOpcode) {}
+};
+
+// Copysign for float32.
+class LCopySignF : public LInstructionHelper<1, 2, 2> {
+ public:
+ LIR_HEADER(CopySignF)
+ explicit LCopySignF() : LInstructionHelper(classOpcode) {}
+};
+
+class LAtan2D : public LCallInstructionHelper<1, 2, 0> {
+ public:
+ LIR_HEADER(Atan2D)
+ LAtan2D(const LAllocation& y, const LAllocation& x)
+ : LCallInstructionHelper(classOpcode) {
+ setOperand(0, y);
+ setOperand(1, x);
+ }
+
+ const LAllocation* y() { return getOperand(0); }
+
+ const LAllocation* x() { return getOperand(1); }
+
+ const LDefinition* output() { return getDef(0); }
+};
+
+class LHypot : public LCallInstructionHelper<1, 4, 0> {
+ uint32_t numOperands_;
+
+ public:
+ LIR_HEADER(Hypot)
+ LHypot(const LAllocation& x, const LAllocation& y)
+ : LCallInstructionHelper(classOpcode), numOperands_(2) {
+ setOperand(0, x);
+ setOperand(1, y);
+ }
+
+ LHypot(const LAllocation& x, const LAllocation& y, const LAllocation& z)
+ : LCallInstructionHelper(classOpcode), numOperands_(3) {
+ setOperand(0, x);
+ setOperand(1, y);
+ setOperand(2, z);
+ }
+
+ LHypot(const LAllocation& x, const LAllocation& y, const LAllocation& z,
+ const LAllocation& w)
+ : LCallInstructionHelper(classOpcode), numOperands_(4) {
+ setOperand(0, x);
+ setOperand(1, y);
+ setOperand(2, z);
+ setOperand(3, w);
+ }
+
+ uint32_t numArgs() const { return numOperands_; }
+
+ const LAllocation* x() { return getOperand(0); }
+
+ const LAllocation* y() { return getOperand(1); }
+
+ const LDefinition* output() { return getDef(0); }
+};
+
+class LMathFunctionD : public LCallInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(MathFunctionD)
+ explicit LMathFunctionD(const LAllocation& input)
+ : LCallInstructionHelper(classOpcode) {
+ setOperand(0, input);
+ }
+
+ MMathFunction* mir() const { return mir_->toMathFunction(); }
+ const char* extraName() const {
+ return MMathFunction::FunctionName(mir()->function());
+ }
+};
+
+class LMathFunctionF : public LCallInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(MathFunctionF)
+ explicit LMathFunctionF(const LAllocation& input)
+ : LCallInstructionHelper(classOpcode) {
+ setOperand(0, input);
+ }
+
+ MMathFunction* mir() const { return mir_->toMathFunction(); }
+ const char* extraName() const {
+ return MMathFunction::FunctionName(mir()->function());
+ }
+};
+
+// Adds two integers, returning an integer value.
+class LAddI : public LBinaryMath<0> {
+ bool recoversInput_;
+
+ public:
+ LIR_HEADER(AddI)
+
+ LAddI() : LBinaryMath(classOpcode), recoversInput_(false) {}
+
+ const char* extraName() const {
+ return snapshot() ? "OverflowCheck" : nullptr;
+ }
+
+ bool recoversInput() const { return recoversInput_; }
+ void setRecoversInput() { recoversInput_ = true; }
+
+ MAdd* mir() const { return mir_->toAdd(); }
+};
+
+class LAddI64 : public LInstructionHelper<INT64_PIECES, 2 * INT64_PIECES, 0> {
+ public:
+ LIR_HEADER(AddI64)
+
+ LAddI64() : LInstructionHelper(classOpcode) {}
+
+ static const size_t Lhs = 0;
+ static const size_t Rhs = INT64_PIECES;
+};
+
+// Subtracts two integers, returning an integer value.
+class LSubI : public LBinaryMath<0> {
+ bool recoversInput_;
+
+ public:
+ LIR_HEADER(SubI)
+
+ LSubI() : LBinaryMath(classOpcode), recoversInput_(false) {}
+
+ const char* extraName() const {
+ return snapshot() ? "OverflowCheck" : nullptr;
+ }
+
+ bool recoversInput() const { return recoversInput_; }
+ void setRecoversInput() { recoversInput_ = true; }
+ MSub* mir() const { return mir_->toSub(); }
+};
+
+inline bool LNode::recoversInput() const {
+ switch (op()) {
+ case Opcode::AddI:
+ return toAddI()->recoversInput();
+ case Opcode::SubI:
+ return toSubI()->recoversInput();
+ default:
+ return false;
+ }
+}
+
+class LSubI64 : public LInstructionHelper<INT64_PIECES, 2 * INT64_PIECES, 0> {
+ public:
+ LIR_HEADER(SubI64)
+
+ static const size_t Lhs = 0;
+ static const size_t Rhs = INT64_PIECES;
+
+ LSubI64() : LInstructionHelper(classOpcode) {}
+};
+
+class LMulI64 : public LInstructionHelper<INT64_PIECES, 2 * INT64_PIECES, 1> {
+ public:
+ LIR_HEADER(MulI64)
+
+ explicit LMulI64() : LInstructionHelper(classOpcode) {
+ setTemp(0, LDefinition());
+ }
+
+ const LDefinition* temp() { return getTemp(0); }
+
+ static const size_t Lhs = 0;
+ static const size_t Rhs = INT64_PIECES;
+};
+
+// Performs an add, sub, mul, or div on two double values.
+class LMathD : public LBinaryMath<0> {
+ JSOp jsop_;
+
+ public:
+ LIR_HEADER(MathD)
+
+ explicit LMathD(JSOp jsop) : LBinaryMath(classOpcode), jsop_(jsop) {}
+
+ JSOp jsop() const { return jsop_; }
+
+ const char* extraName() const { return CodeName(jsop_); }
+};
+
+// Performs an add, sub, mul, or div on two double values.
+class LMathF : public LBinaryMath<0> {
+ JSOp jsop_;
+
+ public:
+ LIR_HEADER(MathF)
+
+ explicit LMathF(JSOp jsop) : LBinaryMath(classOpcode), jsop_(jsop) {}
+
+ JSOp jsop() const { return jsop_; }
+
+ const char* extraName() const { return CodeName(jsop_); }
+};
+
+class LModD : public LBinaryMath<1> {
+ public:
+ LIR_HEADER(ModD)
+
+ LModD(const LAllocation& lhs, const LAllocation& rhs)
+ : LBinaryMath(classOpcode) {
+ setOperand(0, lhs);
+ setOperand(1, rhs);
+ setIsCall();
+ }
+ MMod* mir() const { return mir_->toMod(); }
+};
+
+class LModPowTwoD : public LInstructionHelper<1, 1, 0> {
+ const uint32_t divisor_;
+
+ public:
+ LIR_HEADER(ModPowTwoD)
+
+ LModPowTwoD(const LAllocation& lhs, uint32_t divisor)
+ : LInstructionHelper(classOpcode), divisor_(divisor) {
+ setOperand(0, lhs);
+ }
+
+ uint32_t divisor() const { return divisor_; }
+ const LAllocation* lhs() { return getOperand(0); }
+ MMod* mir() const { return mir_->toMod(); }
+};
+
+class LBigIntAdd : public LBinaryMath<2> {
+ public:
+ LIR_HEADER(BigIntAdd)
+
+ LBigIntAdd(const LAllocation& lhs, const LAllocation& rhs,
+ const LDefinition& temp1, const LDefinition& temp2)
+ : LBinaryMath(classOpcode) {
+ setOperand(0, lhs);
+ setOperand(1, rhs);
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ }
+
+ const LDefinition* temp1() { return getTemp(0); }
+ const LDefinition* temp2() { return getTemp(1); }
+};
+
+class LBigIntSub : public LBinaryMath<2> {
+ public:
+ LIR_HEADER(BigIntSub)
+
+ LBigIntSub(const LAllocation& lhs, const LAllocation& rhs,
+ const LDefinition& temp1, const LDefinition& temp2)
+ : LBinaryMath(classOpcode) {
+ setOperand(0, lhs);
+ setOperand(1, rhs);
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ }
+
+ const LDefinition* temp1() { return getTemp(0); }
+ const LDefinition* temp2() { return getTemp(1); }
+};
+
+class LBigIntMul : public LBinaryMath<2> {
+ public:
+ LIR_HEADER(BigIntMul)
+
+ LBigIntMul(const LAllocation& lhs, const LAllocation& rhs,
+ const LDefinition& temp1, const LDefinition& temp2)
+ : LBinaryMath(classOpcode) {
+ setOperand(0, lhs);
+ setOperand(1, rhs);
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ }
+
+ const LDefinition* temp1() { return getTemp(0); }
+ const LDefinition* temp2() { return getTemp(1); }
+};
+
+class LBigIntDiv : public LBinaryMath<2> {
+ public:
+ LIR_HEADER(BigIntDiv)
+
+ LBigIntDiv(const LAllocation& lhs, const LAllocation& rhs,
+ const LDefinition& temp1, const LDefinition& temp2)
+ : LBinaryMath(classOpcode) {
+ setOperand(0, lhs);
+ setOperand(1, rhs);
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ }
+
+ const LDefinition* temp1() { return getTemp(0); }
+ const LDefinition* temp2() { return getTemp(1); }
+
+ const MBigIntDiv* mir() const { return mirRaw()->toBigIntDiv(); }
+};
+
+class LBigIntMod : public LBinaryMath<2> {
+ public:
+ LIR_HEADER(BigIntMod)
+
+ LBigIntMod(const LAllocation& lhs, const LAllocation& rhs,
+ const LDefinition& temp1, const LDefinition& temp2)
+ : LBinaryMath(classOpcode) {
+ setOperand(0, lhs);
+ setOperand(1, rhs);
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ }
+
+ const LDefinition* temp1() { return getTemp(0); }
+ const LDefinition* temp2() { return getTemp(1); }
+
+ const MBigIntMod* mir() const { return mirRaw()->toBigIntMod(); }
+};
+
+class LBigIntPow : public LBinaryMath<2> {
+ public:
+ LIR_HEADER(BigIntPow)
+
+ LBigIntPow(const LAllocation& lhs, const LAllocation& rhs,
+ const LDefinition& temp1, const LDefinition& temp2)
+ : LBinaryMath(classOpcode) {
+ setOperand(0, lhs);
+ setOperand(1, rhs);
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ }
+
+ const LDefinition* temp1() { return getTemp(0); }
+ const LDefinition* temp2() { return getTemp(1); }
+
+ const MBigIntPow* mir() const { return mirRaw()->toBigIntPow(); }
+};
+
+class LBigIntBitAnd : public LBinaryMath<2> {
+ public:
+ LIR_HEADER(BigIntBitAnd)
+
+ LBigIntBitAnd(const LAllocation& lhs, const LAllocation& rhs,
+ const LDefinition& temp1, const LDefinition& temp2)
+ : LBinaryMath(classOpcode) {
+ setOperand(0, lhs);
+ setOperand(1, rhs);
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ }
+
+ const LDefinition* temp1() { return getTemp(0); }
+ const LDefinition* temp2() { return getTemp(1); }
+};
+
+class LBigIntBitOr : public LBinaryMath<2> {
+ public:
+ LIR_HEADER(BigIntBitOr)
+
+ LBigIntBitOr(const LAllocation& lhs, const LAllocation& rhs,
+ const LDefinition& temp1, const LDefinition& temp2)
+ : LBinaryMath(classOpcode) {
+ setOperand(0, lhs);
+ setOperand(1, rhs);
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ }
+
+ const LDefinition* temp1() { return getTemp(0); }
+ const LDefinition* temp2() { return getTemp(1); }
+};
+
+class LBigIntBitXor : public LBinaryMath<2> {
+ public:
+ LIR_HEADER(BigIntBitXor)
+
+ LBigIntBitXor(const LAllocation& lhs, const LAllocation& rhs,
+ const LDefinition& temp1, const LDefinition& temp2)
+ : LBinaryMath(classOpcode) {
+ setOperand(0, lhs);
+ setOperand(1, rhs);
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ }
+
+ const LDefinition* temp1() { return getTemp(0); }
+ const LDefinition* temp2() { return getTemp(1); }
+};
+
+class LBigIntLsh : public LBinaryMath<3> {
+ public:
+ LIR_HEADER(BigIntLsh)
+
+ LBigIntLsh(const LAllocation& lhs, const LAllocation& rhs,
+ const LDefinition& temp1, const LDefinition& temp2,
+ const LDefinition& temp3)
+ : LBinaryMath(classOpcode) {
+ setOperand(0, lhs);
+ setOperand(1, rhs);
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ setTemp(2, temp3);
+ }
+
+ const LDefinition* temp1() { return getTemp(0); }
+ const LDefinition* temp2() { return getTemp(1); }
+ const LDefinition* temp3() { return getTemp(2); }
+};
+
+class LBigIntRsh : public LBinaryMath<3> {
+ public:
+ LIR_HEADER(BigIntRsh)
+
+ LBigIntRsh(const LAllocation& lhs, const LAllocation& rhs,
+ const LDefinition& temp1, const LDefinition& temp2,
+ const LDefinition& temp3)
+ : LBinaryMath(classOpcode) {
+ setOperand(0, lhs);
+ setOperand(1, rhs);
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ setTemp(2, temp3);
+ }
+
+ const LDefinition* temp1() { return getTemp(0); }
+ const LDefinition* temp2() { return getTemp(1); }
+ const LDefinition* temp3() { return getTemp(2); }
+};
+
+class LBigIntIncrement : public LUnaryMath<2> {
+ public:
+ LIR_HEADER(BigIntIncrement)
+
+ LBigIntIncrement(const LAllocation& input, const LDefinition& temp1,
+ const LDefinition& temp2)
+ : LUnaryMath(classOpcode) {
+ setOperand(0, input);
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ }
+
+ const LDefinition* temp1() { return getTemp(0); }
+ const LDefinition* temp2() { return getTemp(1); }
+};
+
+class LBigIntDecrement : public LUnaryMath<2> {
+ public:
+ LIR_HEADER(BigIntDecrement)
+
+ LBigIntDecrement(const LAllocation& input, const LDefinition& temp1,
+ const LDefinition& temp2)
+ : LUnaryMath(classOpcode) {
+ setOperand(0, input);
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ }
+
+ const LDefinition* temp1() { return getTemp(0); }
+ const LDefinition* temp2() { return getTemp(1); }
+};
+
+class LBigIntNegate : public LUnaryMath<1> {
+ public:
+ LIR_HEADER(BigIntNegate)
+
+ LBigIntNegate(const LAllocation& input, const LDefinition& temp)
+ : LUnaryMath(classOpcode) {
+ setOperand(0, input);
+ setTemp(0, temp);
+ }
+
+ const LDefinition* temp() { return getTemp(0); }
+};
+
+class LBigIntBitNot : public LUnaryMath<2> {
+ public:
+ LIR_HEADER(BigIntBitNot)
+
+ LBigIntBitNot(const LAllocation& input, const LDefinition& temp1,
+ const LDefinition& temp2)
+ : LUnaryMath(classOpcode) {
+ setOperand(0, input);
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ }
+
+ const LDefinition* temp1() { return getTemp(0); }
+ const LDefinition* temp2() { return getTemp(1); }
+};
+
+// Convert a value to an int32.
+// Input: components of a Value
+// Output: 32-bit integer
+// Bailout: undefined, string, object, or non-int32 double
+// Temps: one float register, one GP register
+//
+// This instruction requires a temporary float register.
+class LValueToInt32 : public LInstructionHelper<1, BOX_PIECES, 2> {
+ public:
+ enum Mode { NORMAL, TRUNCATE };
+
+ private:
+ Mode mode_;
+
+ public:
+ LIR_HEADER(ValueToInt32)
+
+ LValueToInt32(const LBoxAllocation& input, const LDefinition& temp0,
+ const LDefinition& temp1, Mode mode)
+ : LInstructionHelper(classOpcode), mode_(mode) {
+ setBoxOperand(Input, input);
+ setTemp(0, temp0);
+ setTemp(1, temp1);
+ }
+
+ const char* extraName() const {
+ switch (mode()) {
+ case NORMAL:
+ return "Normal";
+ case TRUNCATE:
+ return "Truncate";
+ }
+ MOZ_CRASH("Invalid mode");
+ }
+
+ static const size_t Input = 0;
+
+ Mode mode() const { return mode_; }
+ const LDefinition* tempFloat() { return getTemp(0); }
+ const LDefinition* temp() { return getTemp(1); }
+ MToNumberInt32* mirNormal() const {
+ MOZ_ASSERT(mode_ == NORMAL);
+ return mir_->toToNumberInt32();
+ }
+ MTruncateToInt32* mirTruncate() const {
+ MOZ_ASSERT(mode_ == TRUNCATE);
+ return mir_->toTruncateToInt32();
+ }
+ MInstruction* mir() const { return mir_->toInstruction(); }
+};
+
+// Double raised to a half power.
+class LPowHalfD : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(PowHalfD);
+ explicit LPowHalfD(const LAllocation& input)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, input);
+ }
+
+ const LAllocation* input() { return getOperand(0); }
+ const LDefinition* output() { return getDef(0); }
+ MPowHalf* mir() const { return mir_->toPowHalf(); }
+};
+
+// Passed the BaselineFrame address in the OsrFrameReg via the IonOsrTempData
+// populated by PrepareOsrTempData.
+//
+// Forwards this object to the LOsrValues for Value materialization.
+class LOsrEntry : public LInstructionHelper<1, 0, 1> {
+ protected:
+ Label label_;
+ uint32_t frameDepth_;
+
+ public:
+ LIR_HEADER(OsrEntry)
+
+ explicit LOsrEntry(const LDefinition& temp)
+ : LInstructionHelper(classOpcode), frameDepth_(0) {
+ setTemp(0, temp);
+ }
+
+ void setFrameDepth(uint32_t depth) { frameDepth_ = depth; }
+ uint32_t getFrameDepth() { return frameDepth_; }
+ Label* label() { return &label_; }
+ const LDefinition* temp() { return getTemp(0); }
+};
+
+// Bailout if index + minimum < 0 or index + maximum >= length.
+class LBoundsCheckRange : public LInstructionHelper<0, 2, 1> {
+ public:
+ LIR_HEADER(BoundsCheckRange)
+
+ LBoundsCheckRange(const LAllocation& index, const LAllocation& length,
+ const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, index);
+ setOperand(1, length);
+ setTemp(0, temp);
+ }
+ const MBoundsCheck* mir() const { return mir_->toBoundsCheck(); }
+ const LAllocation* index() { return getOperand(0); }
+ const LAllocation* length() { return getOperand(1); }
+};
+
+// Load a value from a dense array's elements vector. Bail out if it's the hole
+// value.
+class LLoadElementV : public LInstructionHelper<BOX_PIECES, 2, 0> {
+ public:
+ LIR_HEADER(LoadElementV)
+
+ LLoadElementV(const LAllocation& elements, const LAllocation& index)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ }
+
+ const MLoadElement* mir() const { return mir_->toLoadElement(); }
+ const LAllocation* elements() { return getOperand(0); }
+ const LAllocation* index() { return getOperand(1); }
+};
+
+// Load a value from an array's elements vector, loading |undefined| if we hit a
+// hole. Bail out if we get a negative index.
+class LLoadElementHole : public LInstructionHelper<BOX_PIECES, 3, 0> {
+ public:
+ LIR_HEADER(LoadElementHole)
+
+ LLoadElementHole(const LAllocation& elements, const LAllocation& index,
+ const LAllocation& initLength)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setOperand(2, initLength);
+ }
+
+ const MLoadElementHole* mir() const { return mir_->toLoadElementHole(); }
+ const LAllocation* elements() { return getOperand(0); }
+ const LAllocation* index() { return getOperand(1); }
+ const LAllocation* initLength() { return getOperand(2); }
+};
+
+// Store a boxed value to a dense array's element vector.
+class LStoreElementV : public LInstructionHelper<0, 2 + BOX_PIECES, 0> {
+ public:
+ LIR_HEADER(StoreElementV)
+
+ LStoreElementV(const LAllocation& elements, const LAllocation& index,
+ const LBoxAllocation& value)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setBoxOperand(Value, value);
+ }
+
+ const char* extraName() const {
+ return mir()->needsHoleCheck() ? "HoleCheck" : nullptr;
+ }
+
+ static const size_t Value = 2;
+
+ const MStoreElement* mir() const { return mir_->toStoreElement(); }
+ const LAllocation* elements() { return getOperand(0); }
+ const LAllocation* index() { return getOperand(1); }
+};
+
+// Store a typed value to a dense array's elements vector. Compared to
+// LStoreElementV, this instruction can store doubles and constants directly,
+// and does not store the type tag if the array is monomorphic and known to
+// be packed.
+class LStoreElementT : public LInstructionHelper<0, 3, 0> {
+ public:
+ LIR_HEADER(StoreElementT)
+
+ LStoreElementT(const LAllocation& elements, const LAllocation& index,
+ const LAllocation& value)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setOperand(2, value);
+ }
+
+ const char* extraName() const {
+ return mir()->needsHoleCheck() ? "HoleCheck" : nullptr;
+ }
+
+ const MStoreElement* mir() const { return mir_->toStoreElement(); }
+ const LAllocation* elements() { return getOperand(0); }
+ const LAllocation* index() { return getOperand(1); }
+ const LAllocation* value() { return getOperand(2); }
+};
+
+class LArrayPopShift : public LInstructionHelper<BOX_PIECES, 1, 2> {
+ public:
+ LIR_HEADER(ArrayPopShift)
+
+ LArrayPopShift(const LAllocation& object, const LDefinition& temp0,
+ const LDefinition& temp1)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, object);
+ setTemp(0, temp0);
+ setTemp(1, temp1);
+ }
+
+ const char* extraName() const {
+ return mir()->mode() == MArrayPopShift::Pop ? "Pop" : "Shift";
+ }
+
+ const MArrayPopShift* mir() const { return mir_->toArrayPopShift(); }
+ const LAllocation* object() { return getOperand(0); }
+ const LDefinition* temp0() { return getTemp(0); }
+ const LDefinition* temp1() { return getTemp(1); }
+};
+
+class LLoadUnboxedBigInt : public LInstructionHelper<1, 2, 1 + INT64_PIECES> {
+ public:
+ LIR_HEADER(LoadUnboxedBigInt)
+
+ LLoadUnboxedBigInt(const LAllocation& elements, const LAllocation& index,
+ const LDefinition& temp, const LInt64Definition& temp64)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setTemp(0, temp);
+ setInt64Temp(1, temp64);
+ }
+ const MLoadUnboxedScalar* mir() const { return mir_->toLoadUnboxedScalar(); }
+ const LAllocation* elements() { return getOperand(0); }
+ const LAllocation* index() { return getOperand(1); }
+ const LDefinition* temp() { return getTemp(0); }
+ const LInt64Definition temp64() { return getInt64Temp(1); }
+};
+
+class LLoadDataViewElement : public LInstructionHelper<1, 3, 1 + INT64_PIECES> {
+ public:
+ LIR_HEADER(LoadDataViewElement)
+
+ LLoadDataViewElement(const LAllocation& elements, const LAllocation& index,
+ const LAllocation& littleEndian, const LDefinition& temp,
+ const LInt64Definition& temp64)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setOperand(2, littleEndian);
+ setTemp(0, temp);
+ setInt64Temp(1, temp64);
+ }
+ const MLoadDataViewElement* mir() const {
+ return mir_->toLoadDataViewElement();
+ }
+ const LAllocation* elements() { return getOperand(0); }
+ const LAllocation* index() { return getOperand(1); }
+ const LAllocation* littleEndian() { return getOperand(2); }
+ const LDefinition* temp() { return getTemp(0); }
+ const LInt64Definition temp64() { return getInt64Temp(1); }
+};
+
+class LLoadTypedArrayElementHoleBigInt
+ : public LInstructionHelper<BOX_PIECES, 2, 1 + INT64_PIECES> {
+ public:
+ LIR_HEADER(LoadTypedArrayElementHoleBigInt)
+
+ LLoadTypedArrayElementHoleBigInt(const LAllocation& object,
+ const LAllocation& index,
+ const LDefinition& temp,
+ const LInt64Definition& temp64)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, object);
+ setOperand(1, index);
+ setTemp(0, temp);
+ setInt64Temp(1, temp64);
+ }
+ const MLoadTypedArrayElementHole* mir() const {
+ return mir_->toLoadTypedArrayElementHole();
+ }
+ const LAllocation* object() { return getOperand(0); }
+ const LAllocation* index() { return getOperand(1); }
+ const LDefinition* temp() { return getTemp(0); }
+ const LInt64Definition temp64() { return getInt64Temp(1); }
+};
+
+class LStoreUnboxedBigInt : public LInstructionHelper<0, 3, INT64_PIECES> {
+ public:
+ LIR_HEADER(StoreUnboxedBigInt)
+
+ LStoreUnboxedBigInt(const LAllocation& elements, const LAllocation& index,
+ const LAllocation& value, const LInt64Definition& temp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setOperand(2, value);
+ setInt64Temp(0, temp);
+ }
+
+ const MStoreUnboxedScalar* mir() const {
+ return mir_->toStoreUnboxedScalar();
+ }
+ const LAllocation* elements() { return getOperand(0); }
+ const LAllocation* index() { return getOperand(1); }
+ const LAllocation* value() { return getOperand(2); }
+ LInt64Definition temp() { return getInt64Temp(0); }
+};
+
+class LStoreDataViewElement
+ : public LInstructionHelper<0, 4, 1 + INT64_PIECES> {
+ public:
+ LIR_HEADER(StoreDataViewElement)
+
+ LStoreDataViewElement(const LAllocation& elements, const LAllocation& index,
+ const LAllocation& value,
+ const LAllocation& littleEndian,
+ const LDefinition& temp, const LInt64Definition& temp64)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setOperand(2, value);
+ setOperand(3, littleEndian);
+ setTemp(0, temp);
+ setInt64Temp(1, temp64);
+ }
+
+ const MStoreDataViewElement* mir() const {
+ return mir_->toStoreDataViewElement();
+ }
+ const LAllocation* elements() { return getOperand(0); }
+ const LAllocation* index() { return getOperand(1); }
+ const LAllocation* value() { return getOperand(2); }
+ const LAllocation* littleEndian() { return getOperand(3); }
+ const LDefinition* temp() { return getTemp(0); }
+ const LInt64Definition temp64() { return getInt64Temp(1); }
+};
+
+class LStoreTypedArrayElementHoleBigInt
+ : public LInstructionHelper<0, 4, INT64_PIECES> {
+ public:
+ LIR_HEADER(StoreTypedArrayElementHoleBigInt)
+
+ LStoreTypedArrayElementHoleBigInt(const LAllocation& elements,
+ const LAllocation& length,
+ const LAllocation& index,
+ const LAllocation& value,
+ const LInt64Definition& temp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, elements);
+ setOperand(1, length);
+ setOperand(2, index);
+ setOperand(3, value);
+ setInt64Temp(0, temp);
+ }
+
+ const MStoreTypedArrayElementHole* mir() const {
+ return mir_->toStoreTypedArrayElementHole();
+ }
+ const LAllocation* elements() { return getOperand(0); }
+ const LAllocation* length() { return getOperand(1); }
+ const LAllocation* index() { return getOperand(2); }
+ const LAllocation* value() { return getOperand(3); }
+ LInt64Definition temp() { return getInt64Temp(0); }
+};
+
+class LCompareExchangeTypedArrayElement : public LInstructionHelper<1, 4, 4> {
+ public:
+ LIR_HEADER(CompareExchangeTypedArrayElement)
+
+ // ARM, ARM64, x86, x64
+ LCompareExchangeTypedArrayElement(const LAllocation& elements,
+ const LAllocation& index,
+ const LAllocation& oldval,
+ const LAllocation& newval,
+ const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setOperand(2, oldval);
+ setOperand(3, newval);
+ setTemp(0, temp);
+ }
+ // MIPS32, MIPS64
+ LCompareExchangeTypedArrayElement(
+ const LAllocation& elements, const LAllocation& index,
+ const LAllocation& oldval, const LAllocation& newval,
+ const LDefinition& temp, const LDefinition& valueTemp,
+ const LDefinition& offsetTemp, const LDefinition& maskTemp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setOperand(2, oldval);
+ setOperand(3, newval);
+ setTemp(0, temp);
+ setTemp(1, valueTemp);
+ setTemp(2, offsetTemp);
+ setTemp(3, maskTemp);
+ }
+
+ const LAllocation* elements() { return getOperand(0); }
+ const LAllocation* index() { return getOperand(1); }
+ const LAllocation* oldval() { return getOperand(2); }
+ const LAllocation* newval() { return getOperand(3); }
+ const LDefinition* temp() { return getTemp(0); }
+
+ // Temp that may be used on LL/SC platforms for extract/insert bits of word.
+ const LDefinition* valueTemp() { return getTemp(1); }
+ const LDefinition* offsetTemp() { return getTemp(2); }
+ const LDefinition* maskTemp() { return getTemp(3); }
+
+ const MCompareExchangeTypedArrayElement* mir() const {
+ return mir_->toCompareExchangeTypedArrayElement();
+ }
+};
+
+class LAtomicExchangeTypedArrayElement : public LInstructionHelper<1, 3, 4> {
+ public:
+ LIR_HEADER(AtomicExchangeTypedArrayElement)
+
+ // ARM, ARM64, x86, x64
+ LAtomicExchangeTypedArrayElement(const LAllocation& elements,
+ const LAllocation& index,
+ const LAllocation& value,
+ const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setOperand(2, value);
+ setTemp(0, temp);
+ }
+ // MIPS32, MIPS64
+ LAtomicExchangeTypedArrayElement(const LAllocation& elements,
+ const LAllocation& index,
+ const LAllocation& value,
+ const LDefinition& temp,
+ const LDefinition& valueTemp,
+ const LDefinition& offsetTemp,
+ const LDefinition& maskTemp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setOperand(2, value);
+ setTemp(0, temp);
+ setTemp(1, valueTemp);
+ setTemp(2, offsetTemp);
+ setTemp(3, maskTemp);
+ }
+
+ const LAllocation* elements() { return getOperand(0); }
+ const LAllocation* index() { return getOperand(1); }
+ const LAllocation* value() { return getOperand(2); }
+ const LDefinition* temp() { return getTemp(0); }
+
+ // Temp that may be used on LL/SC platforms for extract/insert bits of word.
+ const LDefinition* valueTemp() { return getTemp(1); }
+ const LDefinition* offsetTemp() { return getTemp(2); }
+ const LDefinition* maskTemp() { return getTemp(3); }
+
+ const MAtomicExchangeTypedArrayElement* mir() const {
+ return mir_->toAtomicExchangeTypedArrayElement();
+ }
+};
+
+class LAtomicTypedArrayElementBinop : public LInstructionHelper<1, 3, 5> {
+ public:
+ LIR_HEADER(AtomicTypedArrayElementBinop)
+
+ static const int32_t valueOp = 2;
+
+ // ARM, ARM64, x86, x64
+ LAtomicTypedArrayElementBinop(const LAllocation& elements,
+ const LAllocation& index,
+ const LAllocation& value,
+ const LDefinition& temp1,
+ const LDefinition& temp2)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setOperand(2, value);
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ }
+ // MIPS32, MIPS64
+ LAtomicTypedArrayElementBinop(const LAllocation& elements,
+ const LAllocation& index,
+ const LAllocation& value,
+ const LDefinition& temp2,
+ const LDefinition& valueTemp,
+ const LDefinition& offsetTemp,
+ const LDefinition& maskTemp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setOperand(2, value);
+ setTemp(0, LDefinition::BogusTemp());
+ setTemp(1, temp2);
+ setTemp(2, valueTemp);
+ setTemp(3, offsetTemp);
+ setTemp(4, maskTemp);
+ }
+
+ const LAllocation* elements() { return getOperand(0); }
+ const LAllocation* index() { return getOperand(1); }
+ const LAllocation* value() {
+ MOZ_ASSERT(valueOp == 2);
+ return getOperand(2);
+ }
+ const LDefinition* temp1() { return getTemp(0); }
+ const LDefinition* temp2() { return getTemp(1); }
+
+ // Temp that may be used on LL/SC platforms for extract/insert bits of word.
+ const LDefinition* valueTemp() { return getTemp(2); }
+ const LDefinition* offsetTemp() { return getTemp(3); }
+ const LDefinition* maskTemp() { return getTemp(4); }
+
+ const MAtomicTypedArrayElementBinop* mir() const {
+ return mir_->toAtomicTypedArrayElementBinop();
+ }
+};
+
+// Atomic binary operation where the result is discarded.
+class LAtomicTypedArrayElementBinopForEffect
+ : public LInstructionHelper<0, 3, 4> {
+ public:
+ LIR_HEADER(AtomicTypedArrayElementBinopForEffect)
+
+ // ARM, ARM64, x86, x64
+ LAtomicTypedArrayElementBinopForEffect(
+ const LAllocation& elements, const LAllocation& index,
+ const LAllocation& value,
+ const LDefinition& flagTemp = LDefinition::BogusTemp())
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setOperand(2, value);
+ setTemp(0, flagTemp);
+ }
+ // MIPS32, MIPS64
+ LAtomicTypedArrayElementBinopForEffect(const LAllocation& elements,
+ const LAllocation& index,
+ const LAllocation& value,
+ const LDefinition& valueTemp,
+ const LDefinition& offsetTemp,
+ const LDefinition& maskTemp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setOperand(2, value);
+ setTemp(0, LDefinition::BogusTemp());
+ setTemp(1, valueTemp);
+ setTemp(2, offsetTemp);
+ setTemp(3, maskTemp);
+ }
+
+ const LAllocation* elements() { return getOperand(0); }
+ const LAllocation* index() { return getOperand(1); }
+ const LAllocation* value() { return getOperand(2); }
+
+ // Temp that may be used on LL/SC platforms for the flag result of the store.
+ const LDefinition* flagTemp() { return getTemp(0); }
+ // Temp that may be used on LL/SC platforms for extract/insert bits of word.
+ const LDefinition* valueTemp() { return getTemp(1); }
+ const LDefinition* offsetTemp() { return getTemp(2); }
+ const LDefinition* maskTemp() { return getTemp(3); }
+
+ const MAtomicTypedArrayElementBinop* mir() const {
+ return mir_->toAtomicTypedArrayElementBinop();
+ }
+};
+
+class LAtomicLoad64 : public LInstructionHelper<1, 2, 1 + INT64_PIECES> {
+ public:
+ LIR_HEADER(AtomicLoad64)
+
+ LAtomicLoad64(const LAllocation& elements, const LAllocation& index,
+ const LDefinition& temp, const LInt64Definition& temp64)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setTemp(0, temp);
+ setInt64Temp(1, temp64);
+ }
+ const MLoadUnboxedScalar* mir() const { return mir_->toLoadUnboxedScalar(); }
+ const LAllocation* elements() { return getOperand(0); }
+ const LAllocation* index() { return getOperand(1); }
+ const LDefinition* temp() { return getTemp(0); }
+ LInt64Definition temp64() { return getInt64Temp(1); }
+};
+
+class LAtomicStore64 : public LInstructionHelper<0, 3, 2 * INT64_PIECES + 1> {
+ public:
+ LIR_HEADER(AtomicStore64)
+
+ // x64, ARM64
+ LAtomicStore64(const LAllocation& elements, const LAllocation& index,
+ const LAllocation& value, const LInt64Definition& temp1)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setOperand(2, value);
+ setInt64Temp(0, temp1);
+ setInt64Temp(INT64_PIECES, LInt64Definition::BogusTemp());
+ setTemp(2 * INT64_PIECES, LDefinition::BogusTemp());
+ }
+
+ // ARM32
+ LAtomicStore64(const LAllocation& elements, const LAllocation& index,
+ const LAllocation& value, const LInt64Definition& temp1,
+ const LInt64Definition& temp2)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setOperand(2, value);
+ setInt64Temp(0, temp1);
+ setInt64Temp(INT64_PIECES, temp2);
+ setTemp(2 * INT64_PIECES, LDefinition::BogusTemp());
+ }
+
+ // x86
+ LAtomicStore64(const LAllocation& elements, const LAllocation& index,
+ const LAllocation& value, const LInt64Definition& temp1,
+ const LDefinition& tempLow)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setOperand(2, value);
+ setInt64Temp(0, temp1);
+ setInt64Temp(INT64_PIECES, LInt64Definition::BogusTemp());
+ setTemp(2 * INT64_PIECES, tempLow);
+ }
+
+ const MStoreUnboxedScalar* mir() const {
+ return mir_->toStoreUnboxedScalar();
+ }
+ const LAllocation* elements() { return getOperand(0); }
+ const LAllocation* index() { return getOperand(1); }
+ const LAllocation* value() { return getOperand(2); }
+ LInt64Definition temp1() { return getInt64Temp(0); }
+ LInt64Definition temp2() { return getInt64Temp(INT64_PIECES); }
+ const LDefinition* tempLow() { return getTemp(2 * INT64_PIECES); }
+};
+
+class LCompareExchangeTypedArrayElement64
+ : public LInstructionHelper<1, 4, 3 * INT64_PIECES + 1> {
+ public:
+ LIR_HEADER(CompareExchangeTypedArrayElement64)
+
+ // x64, ARM64
+ LCompareExchangeTypedArrayElement64(const LAllocation& elements,
+ const LAllocation& index,
+ const LAllocation& oldval,
+ const LAllocation& newval,
+ const LInt64Definition& temp1,
+ const LInt64Definition& temp2)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setOperand(2, oldval);
+ setOperand(3, newval);
+ setInt64Temp(0, temp1);
+ setInt64Temp(INT64_PIECES, temp2);
+ setInt64Temp(2 * INT64_PIECES, LInt64Definition::BogusTemp());
+ setTemp(3 * INT64_PIECES, LDefinition::BogusTemp());
+ }
+
+ // x86
+ LCompareExchangeTypedArrayElement64(const LAllocation& elements,
+ const LAllocation& index,
+ const LAllocation& oldval,
+ const LAllocation& newval,
+ const LDefinition& tempLow)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setOperand(2, oldval);
+ setOperand(3, newval);
+ setInt64Temp(0, LInt64Definition::BogusTemp());
+ setInt64Temp(INT64_PIECES, LInt64Definition::BogusTemp());
+ setInt64Temp(2 * INT64_PIECES, LInt64Definition::BogusTemp());
+ setTemp(3 * INT64_PIECES, tempLow);
+ }
+
+ // ARM
+ LCompareExchangeTypedArrayElement64(const LAllocation& elements,
+ const LAllocation& index,
+ const LAllocation& oldval,
+ const LAllocation& newval,
+ const LInt64Definition& temp1,
+ const LInt64Definition& temp2,
+ const LInt64Definition& temp3)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setOperand(2, oldval);
+ setOperand(3, newval);
+ setInt64Temp(0, temp1);
+ setInt64Temp(INT64_PIECES, temp2);
+ setInt64Temp(2 * INT64_PIECES, temp3);
+ setTemp(3 * INT64_PIECES, LDefinition::BogusTemp());
+ }
+
+ const MCompareExchangeTypedArrayElement* mir() const {
+ return mir_->toCompareExchangeTypedArrayElement();
+ }
+ const LAllocation* elements() { return getOperand(0); }
+ const LAllocation* index() { return getOperand(1); }
+ const LAllocation* oldval() { return getOperand(2); }
+ const LAllocation* newval() { return getOperand(3); }
+ LInt64Definition temp1() { return getInt64Temp(0); }
+ LInt64Definition temp2() { return getInt64Temp(INT64_PIECES); }
+ LInt64Definition temp3() { return getInt64Temp(2 * INT64_PIECES); }
+ const LDefinition* tempLow() { return getTemp(3 * INT64_PIECES); }
+};
+
+class LAtomicExchangeTypedArrayElement64
+ : public LInstructionHelper<1, 3, INT64_PIECES + 1> {
+ public:
+ LIR_HEADER(AtomicExchangeTypedArrayElement64)
+
+ // ARM, ARM64, x64
+ LAtomicExchangeTypedArrayElement64(const LAllocation& elements,
+ const LAllocation& index,
+ const LAllocation& value,
+ const LInt64Definition& temp1,
+ const LDefinition& temp2)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setOperand(2, value);
+ setInt64Temp(0, temp1);
+ setTemp(INT64_PIECES, temp2);
+ }
+
+ // x86
+ LAtomicExchangeTypedArrayElement64(const LAllocation& elements,
+ const LAllocation& index,
+ const LAllocation& value,
+ const LInt64Definition& temp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setOperand(2, value);
+ setInt64Temp(0, temp);
+ setTemp(INT64_PIECES, LDefinition::BogusTemp());
+ }
+
+ const LAllocation* elements() { return getOperand(0); }
+ const LAllocation* index() { return getOperand(1); }
+ const LAllocation* value() { return getOperand(2); }
+ LInt64Definition temp1() { return getInt64Temp(0); }
+ const LDefinition* temp2() { return getTemp(INT64_PIECES); }
+
+ const MAtomicExchangeTypedArrayElement* mir() const {
+ return mir_->toAtomicExchangeTypedArrayElement();
+ }
+};
+
+class LAtomicTypedArrayElementBinop64
+ : public LInstructionHelper<1, 3, 3 * INT64_PIECES> {
+ public:
+ LIR_HEADER(AtomicTypedArrayElementBinop64)
+
+ // x86
+ LAtomicTypedArrayElementBinop64(const LAllocation& elements,
+ const LAllocation& index,
+ const LAllocation& value,
+ const LInt64Definition& temp1)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setOperand(2, value);
+ setInt64Temp(0, temp1);
+ setInt64Temp(INT64_PIECES, LInt64Definition::BogusTemp());
+ setInt64Temp(2 * INT64_PIECES, LInt64Definition::BogusTemp());
+ }
+
+ // ARM64, x64
+ LAtomicTypedArrayElementBinop64(const LAllocation& elements,
+ const LAllocation& index,
+ const LAllocation& value,
+ const LInt64Definition& temp1,
+ const LInt64Definition& temp2)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setOperand(2, value);
+ setInt64Temp(0, temp1);
+ setInt64Temp(INT64_PIECES, temp2);
+ setInt64Temp(2 * INT64_PIECES, LInt64Definition::BogusTemp());
+ }
+
+ // ARM
+ LAtomicTypedArrayElementBinop64(const LAllocation& elements,
+ const LAllocation& index,
+ const LAllocation& value,
+ const LInt64Definition& temp1,
+ const LInt64Definition& temp2,
+ const LInt64Definition& temp3)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setOperand(2, value);
+ setInt64Temp(0, temp1);
+ setInt64Temp(INT64_PIECES, temp2);
+ setInt64Temp(2 * INT64_PIECES, temp3);
+ }
+
+ const LAllocation* elements() { return getOperand(0); }
+ const LAllocation* index() { return getOperand(1); }
+ const LAllocation* value() { return getOperand(2); }
+ LInt64Definition temp1() { return getInt64Temp(0); }
+ LInt64Definition temp2() { return getInt64Temp(INT64_PIECES); }
+ LInt64Definition temp3() { return getInt64Temp(2 * INT64_PIECES); }
+
+ const MAtomicTypedArrayElementBinop* mir() const {
+ return mir_->toAtomicTypedArrayElementBinop();
+ }
+};
+
+// Atomic binary operation where the result is discarded.
+class LAtomicTypedArrayElementBinopForEffect64
+ : public LInstructionHelper<0, 3, 2 * INT64_PIECES + 1> {
+ public:
+ LIR_HEADER(AtomicTypedArrayElementBinopForEffect64)
+
+ // x86
+ LAtomicTypedArrayElementBinopForEffect64(const LAllocation& elements,
+ const LAllocation& index,
+ const LAllocation& value,
+ const LInt64Definition& temp,
+ const LDefinition& tempLow)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setOperand(2, value);
+ setInt64Temp(0, temp);
+ setInt64Temp(INT64_PIECES, LInt64Definition::BogusTemp());
+ setTemp(2 * INT64_PIECES, tempLow);
+ }
+
+ // x64
+ LAtomicTypedArrayElementBinopForEffect64(const LAllocation& elements,
+ const LAllocation& index,
+ const LAllocation& value,
+ const LInt64Definition& temp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setOperand(2, value);
+ setInt64Temp(0, temp);
+ setInt64Temp(INT64_PIECES, LInt64Definition::BogusTemp());
+ setTemp(2 * INT64_PIECES, LDefinition::BogusTemp());
+ }
+
+ // ARM64
+ LAtomicTypedArrayElementBinopForEffect64(const LAllocation& elements,
+ const LAllocation& index,
+ const LAllocation& value,
+ const LInt64Definition& temp1,
+ const LInt64Definition& temp2)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setOperand(2, value);
+ setInt64Temp(0, temp1);
+ setInt64Temp(INT64_PIECES, temp2);
+ setTemp(2 * INT64_PIECES, LDefinition::BogusTemp());
+ }
+
+ const LAllocation* elements() { return getOperand(0); }
+ const LAllocation* index() { return getOperand(1); }
+ const LAllocation* value() { return getOperand(2); }
+ LInt64Definition temp1() { return getInt64Temp(0); }
+ LInt64Definition temp2() { return getInt64Temp(INT64_PIECES); }
+ const LDefinition* tempLow() { return getTemp(2 * INT64_PIECES); }
+
+ const MAtomicTypedArrayElementBinop* mir() const {
+ return mir_->toAtomicTypedArrayElementBinop();
+ }
+};
+
+class LIteratorHasIndicesAndBranch : public LControlInstructionHelper<2, 2, 2> {
+ public:
+ LIR_HEADER(IteratorHasIndicesAndBranch)
+
+ LIteratorHasIndicesAndBranch(MBasicBlock* ifTrue, MBasicBlock* ifFalse,
+ const LAllocation& object,
+ const LAllocation& iterator,
+ const LDefinition& temp,
+ const LDefinition& temp2)
+ : LControlInstructionHelper(classOpcode) {
+ setSuccessor(0, ifTrue);
+ setSuccessor(1, ifFalse);
+ setOperand(0, object);
+ setOperand(1, iterator);
+ setTemp(0, temp);
+ setTemp(1, temp2);
+ }
+
+ const LAllocation* object() { return getOperand(0); }
+ const LAllocation* iterator() { return getOperand(1); }
+ const LDefinition* temp() { return getTemp(0); }
+ const LDefinition* temp2() { return getTemp(1); }
+
+ MBasicBlock* ifTrue() const { return getSuccessor(0); }
+ MBasicBlock* ifFalse() const { return getSuccessor(1); }
+};
+
+class LIsNoIterAndBranch : public LControlInstructionHelper<2, BOX_PIECES, 0> {
+ public:
+ LIR_HEADER(IsNoIterAndBranch)
+
+ LIsNoIterAndBranch(MBasicBlock* ifTrue, MBasicBlock* ifFalse,
+ const LBoxAllocation& input)
+ : LControlInstructionHelper(classOpcode) {
+ setSuccessor(0, ifTrue);
+ setSuccessor(1, ifFalse);
+ setBoxOperand(Input, input);
+ }
+
+ static const size_t Input = 0;
+
+ MBasicBlock* ifTrue() const { return getSuccessor(0); }
+ MBasicBlock* ifFalse() const { return getSuccessor(1); }
+};
+
+class LInstanceOfCache : public LInstructionHelper<1, BOX_PIECES + 1, 0> {
+ public:
+ LIR_HEADER(InstanceOfCache)
+ LInstanceOfCache(const LBoxAllocation& lhs, const LAllocation& rhs)
+ : LInstructionHelper(classOpcode) {
+ setBoxOperand(LHS, lhs);
+ setOperand(RHS, rhs);
+ }
+
+ const LDefinition* output() { return this->getDef(0); }
+ const LAllocation* rhs() { return getOperand(RHS); }
+
+ static const size_t LHS = 0;
+ static const size_t RHS = BOX_PIECES;
+};
+
+class LIsObjectAndBranch : public LControlInstructionHelper<2, BOX_PIECES, 0> {
+ public:
+ LIR_HEADER(IsObjectAndBranch)
+
+ LIsObjectAndBranch(MBasicBlock* ifTrue, MBasicBlock* ifFalse,
+ const LBoxAllocation& input)
+ : LControlInstructionHelper(classOpcode) {
+ setSuccessor(0, ifTrue);
+ setSuccessor(1, ifFalse);
+ setBoxOperand(Input, input);
+ }
+
+ static const size_t Input = 0;
+
+ MBasicBlock* ifTrue() const { return getSuccessor(0); }
+ MBasicBlock* ifFalse() const { return getSuccessor(1); }
+};
+
+class LIsNullOrUndefinedAndBranch
+ : public LControlInstructionHelper<2, BOX_PIECES, 0> {
+ MIsNullOrUndefined* isNullOrUndefined_;
+
+ public:
+ LIR_HEADER(IsNullOrUndefinedAndBranch)
+ static const size_t Input = 0;
+
+ LIsNullOrUndefinedAndBranch(MIsNullOrUndefined* isNullOrUndefined,
+ MBasicBlock* ifTrue, MBasicBlock* ifFalse,
+ const LBoxAllocation& input)
+ : LControlInstructionHelper(classOpcode),
+ isNullOrUndefined_(isNullOrUndefined) {
+ setSuccessor(0, ifTrue);
+ setSuccessor(1, ifFalse);
+ setBoxOperand(Input, input);
+ }
+
+ MBasicBlock* ifTrue() const { return getSuccessor(0); }
+ MBasicBlock* ifFalse() const { return getSuccessor(1); }
+
+ MIsNullOrUndefined* isNullOrUndefinedMir() const {
+ return isNullOrUndefined_;
+ }
+};
+
+template <size_t Defs, size_t Ops>
+class LWasmSelectBase : public LInstructionHelper<Defs, Ops, 0> {
+ typedef LInstructionHelper<Defs, Ops, 0> Base;
+
+ protected:
+ explicit LWasmSelectBase(LNode::Opcode opcode) : Base(opcode) {}
+
+ public:
+ MWasmSelect* mir() const { return Base::mir_->toWasmSelect(); }
+};
+
+class LWasmSelect : public LWasmSelectBase<1, 3> {
+ public:
+ LIR_HEADER(WasmSelect);
+
+ static const size_t TrueExprIndex = 0;
+ static const size_t FalseExprIndex = 1;
+ static const size_t CondIndex = 2;
+
+ LWasmSelect(const LAllocation& trueExpr, const LAllocation& falseExpr,
+ const LAllocation& cond)
+ : LWasmSelectBase(classOpcode) {
+ setOperand(TrueExprIndex, trueExpr);
+ setOperand(FalseExprIndex, falseExpr);
+ setOperand(CondIndex, cond);
+ }
+
+ const LAllocation* trueExpr() { return getOperand(TrueExprIndex); }
+ const LAllocation* falseExpr() { return getOperand(FalseExprIndex); }
+ const LAllocation* condExpr() { return getOperand(CondIndex); }
+};
+
+class LWasmSelectI64
+ : public LWasmSelectBase<INT64_PIECES, 2 * INT64_PIECES + 1> {
+ public:
+ LIR_HEADER(WasmSelectI64);
+
+ static const size_t TrueExprIndex = 0;
+ static const size_t FalseExprIndex = INT64_PIECES;
+ static const size_t CondIndex = INT64_PIECES * 2;
+
+ LWasmSelectI64(const LInt64Allocation& trueExpr,
+ const LInt64Allocation& falseExpr, const LAllocation& cond)
+ : LWasmSelectBase(classOpcode) {
+ setInt64Operand(TrueExprIndex, trueExpr);
+ setInt64Operand(FalseExprIndex, falseExpr);
+ setOperand(CondIndex, cond);
+ }
+
+ const LInt64Allocation trueExpr() { return getInt64Operand(TrueExprIndex); }
+ const LInt64Allocation falseExpr() { return getInt64Operand(FalseExprIndex); }
+ const LAllocation* condExpr() { return getOperand(CondIndex); }
+};
+
+class LWasmCompareAndSelect : public LWasmSelectBase<1, 4> {
+ MCompare::CompareType compareType_;
+ JSOp jsop_;
+
+ public:
+ LIR_HEADER(WasmCompareAndSelect);
+
+ static const size_t LeftExprIndex = 0;
+ static const size_t RightExprIndex = 1;
+ static const size_t IfTrueExprIndex = 2;
+ static const size_t IfFalseExprIndex = 3;
+
+ LWasmCompareAndSelect(const LAllocation& leftExpr,
+ const LAllocation& rightExpr,
+ MCompare::CompareType compareType, JSOp jsop,
+ const LAllocation& ifTrueExpr,
+ const LAllocation& ifFalseExpr)
+ : LWasmSelectBase(classOpcode), compareType_(compareType), jsop_(jsop) {
+ setOperand(LeftExprIndex, leftExpr);
+ setOperand(RightExprIndex, rightExpr);
+ setOperand(IfTrueExprIndex, ifTrueExpr);
+ setOperand(IfFalseExprIndex, ifFalseExpr);
+ }
+
+ const LAllocation* leftExpr() { return getOperand(LeftExprIndex); }
+ const LAllocation* rightExpr() { return getOperand(RightExprIndex); }
+ const LAllocation* ifTrueExpr() { return getOperand(IfTrueExprIndex); }
+ const LAllocation* ifFalseExpr() { return getOperand(IfFalseExprIndex); }
+
+ MCompare::CompareType compareType() { return compareType_; }
+ JSOp jsop() { return jsop_; }
+};
+
+class LWasmBoundsCheck64
+ : public LInstructionHelper<INT64_PIECES, 2 * INT64_PIECES, 0> {
+ public:
+ LIR_HEADER(WasmBoundsCheck64);
+ explicit LWasmBoundsCheck64(const LInt64Allocation& ptr,
+ const LInt64Allocation& boundsCheckLimit)
+ : LInstructionHelper(classOpcode) {
+ setInt64Operand(0, ptr);
+ setInt64Operand(INT64_PIECES, boundsCheckLimit);
+ }
+ MWasmBoundsCheck* mir() const { return mir_->toWasmBoundsCheck(); }
+ LInt64Allocation ptr() { return getInt64Operand(0); }
+ LInt64Allocation boundsCheckLimit() { return getInt64Operand(INT64_PIECES); }
+};
+
+namespace details {
+
+// This is a base class for LWasmLoad/LWasmLoadI64.
+template <size_t Defs, size_t Temp>
+class LWasmLoadBase : public LInstructionHelper<Defs, 2, Temp> {
+ public:
+ typedef LInstructionHelper<Defs, 2, Temp> Base;
+ explicit LWasmLoadBase(LNode::Opcode opcode, const LAllocation& ptr,
+ const LAllocation& memoryBase)
+ : Base(opcode) {
+ Base::setOperand(0, ptr);
+ Base::setOperand(1, memoryBase);
+ }
+ MWasmLoad* mir() const { return Base::mir_->toWasmLoad(); }
+ const LAllocation* ptr() { return Base::getOperand(0); }
+ const LAllocation* memoryBase() { return Base::getOperand(1); }
+};
+
+} // namespace details
+
+class LWasmLoad : public details::LWasmLoadBase<1, 1> {
+ public:
+ explicit LWasmLoad(const LAllocation& ptr,
+ const LAllocation& memoryBase = LAllocation())
+ : LWasmLoadBase(classOpcode, ptr, memoryBase) {
+ setTemp(0, LDefinition::BogusTemp());
+ }
+
+ const LDefinition* ptrCopy() { return Base::getTemp(0); }
+
+ LIR_HEADER(WasmLoad);
+};
+
+class LWasmLoadI64 : public details::LWasmLoadBase<INT64_PIECES, 1> {
+ public:
+ explicit LWasmLoadI64(const LAllocation& ptr,
+ const LAllocation& memoryBase = LAllocation())
+ : LWasmLoadBase(classOpcode, ptr, memoryBase) {
+ setTemp(0, LDefinition::BogusTemp());
+ }
+
+ const LDefinition* ptrCopy() { return Base::getTemp(0); }
+
+ LIR_HEADER(WasmLoadI64);
+};
+
+class LWasmStore : public LInstructionHelper<0, 3, 1> {
+ public:
+ LIR_HEADER(WasmStore);
+
+ static const size_t PtrIndex = 0;
+ static const size_t ValueIndex = 1;
+ static const size_t MemoryBaseIndex = 2;
+
+ LWasmStore(const LAllocation& ptr, const LAllocation& value,
+ const LAllocation& memoryBase = LAllocation())
+ : LInstructionHelper(classOpcode) {
+ setOperand(PtrIndex, ptr);
+ setOperand(ValueIndex, value);
+ setOperand(MemoryBaseIndex, memoryBase);
+ setTemp(0, LDefinition::BogusTemp());
+ }
+ MWasmStore* mir() const { return mir_->toWasmStore(); }
+ const LAllocation* ptr() { return getOperand(PtrIndex); }
+ const LDefinition* ptrCopy() { return getTemp(0); }
+ const LAllocation* value() { return getOperand(ValueIndex); }
+ const LAllocation* memoryBase() { return getOperand(MemoryBaseIndex); }
+};
+
+class LWasmStoreI64 : public LInstructionHelper<0, INT64_PIECES + 2, 1> {
+ public:
+ LIR_HEADER(WasmStoreI64);
+
+ static const size_t PtrIndex = 0;
+ static const size_t MemoryBaseIndex = 1;
+ static const size_t ValueIndex = 2;
+
+ LWasmStoreI64(const LAllocation& ptr, const LInt64Allocation& value,
+ const LAllocation& memoryBase = LAllocation())
+ : LInstructionHelper(classOpcode) {
+ setOperand(PtrIndex, ptr);
+ setOperand(MemoryBaseIndex, memoryBase);
+ setInt64Operand(ValueIndex, value);
+ setTemp(0, LDefinition::BogusTemp());
+ }
+ MWasmStore* mir() const { return mir_->toWasmStore(); }
+ const LAllocation* ptr() { return getOperand(PtrIndex); }
+ const LAllocation* memoryBase() { return getOperand(MemoryBaseIndex); }
+ const LDefinition* ptrCopy() { return getTemp(0); }
+ const LInt64Allocation value() { return getInt64Operand(ValueIndex); }
+};
+
+class LWasmCompareExchangeHeap : public LInstructionHelper<1, 4, 4> {
+ public:
+ LIR_HEADER(WasmCompareExchangeHeap);
+
+ // ARM, ARM64, x86, x64
+ LWasmCompareExchangeHeap(const LAllocation& ptr, const LAllocation& oldValue,
+ const LAllocation& newValue,
+ const LAllocation& memoryBase = LAllocation())
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, ptr);
+ setOperand(1, oldValue);
+ setOperand(2, newValue);
+ setOperand(3, memoryBase);
+ setTemp(0, LDefinition::BogusTemp());
+ }
+ // MIPS32, MIPS64
+ LWasmCompareExchangeHeap(const LAllocation& ptr, const LAllocation& oldValue,
+ const LAllocation& newValue,
+ const LDefinition& valueTemp,
+ const LDefinition& offsetTemp,
+ const LDefinition& maskTemp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, ptr);
+ setOperand(1, oldValue);
+ setOperand(2, newValue);
+ setOperand(3, LAllocation());
+ setTemp(0, LDefinition::BogusTemp());
+ setTemp(1, valueTemp);
+ setTemp(2, offsetTemp);
+ setTemp(3, maskTemp);
+ }
+
+ const LAllocation* ptr() { return getOperand(0); }
+ const LAllocation* oldValue() { return getOperand(1); }
+ const LAllocation* newValue() { return getOperand(2); }
+ const LAllocation* memoryBase() { return getOperand(3); }
+ const LDefinition* addrTemp() { return getTemp(0); }
+
+ void setAddrTemp(const LDefinition& addrTemp) { setTemp(0, addrTemp); }
+
+ // Temp that may be used on LL/SC platforms for extract/insert bits of word.
+ const LDefinition* valueTemp() { return getTemp(1); }
+ const LDefinition* offsetTemp() { return getTemp(2); }
+ const LDefinition* maskTemp() { return getTemp(3); }
+
+ MWasmCompareExchangeHeap* mir() const {
+ return mir_->toWasmCompareExchangeHeap();
+ }
+};
+
+class LWasmAtomicExchangeHeap : public LInstructionHelper<1, 3, 4> {
+ public:
+ LIR_HEADER(WasmAtomicExchangeHeap);
+
+ // ARM, ARM64, x86, x64
+ LWasmAtomicExchangeHeap(const LAllocation& ptr, const LAllocation& value,
+ const LAllocation& memoryBase = LAllocation())
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, ptr);
+ setOperand(1, value);
+ setOperand(2, memoryBase);
+ setTemp(0, LDefinition::BogusTemp());
+ }
+ // MIPS32, MIPS64
+ LWasmAtomicExchangeHeap(const LAllocation& ptr, const LAllocation& value,
+ const LDefinition& valueTemp,
+ const LDefinition& offsetTemp,
+ const LDefinition& maskTemp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, ptr);
+ setOperand(1, value);
+ setOperand(2, LAllocation());
+ setTemp(0, LDefinition::BogusTemp());
+ setTemp(1, valueTemp);
+ setTemp(2, offsetTemp);
+ setTemp(3, maskTemp);
+ }
+
+ const LAllocation* ptr() { return getOperand(0); }
+ const LAllocation* value() { return getOperand(1); }
+ const LAllocation* memoryBase() { return getOperand(2); }
+ const LDefinition* addrTemp() { return getTemp(0); }
+
+ void setAddrTemp(const LDefinition& addrTemp) { setTemp(0, addrTemp); }
+
+ // Temp that may be used on LL/SC platforms for extract/insert bits of word.
+ const LDefinition* valueTemp() { return getTemp(1); }
+ const LDefinition* offsetTemp() { return getTemp(2); }
+ const LDefinition* maskTemp() { return getTemp(3); }
+
+ MWasmAtomicExchangeHeap* mir() const {
+ return mir_->toWasmAtomicExchangeHeap();
+ }
+};
+
+class LWasmAtomicBinopHeap : public LInstructionHelper<1, 3, 6> {
+ public:
+ LIR_HEADER(WasmAtomicBinopHeap);
+
+ static const int32_t valueOp = 1;
+
+ // ARM, ARM64, x86, x64
+ LWasmAtomicBinopHeap(const LAllocation& ptr, const LAllocation& value,
+ const LDefinition& temp,
+ const LDefinition& flagTemp = LDefinition::BogusTemp(),
+ const LAllocation& memoryBase = LAllocation())
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, ptr);
+ setOperand(1, value);
+ setOperand(2, memoryBase);
+ setTemp(0, temp);
+ setTemp(1, LDefinition::BogusTemp());
+ setTemp(2, flagTemp);
+ }
+ // MIPS32, MIPS64
+ LWasmAtomicBinopHeap(const LAllocation& ptr, const LAllocation& value,
+ const LDefinition& valueTemp,
+ const LDefinition& offsetTemp,
+ const LDefinition& maskTemp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, ptr);
+ setOperand(1, value);
+ setOperand(2, LAllocation());
+ setTemp(0, LDefinition::BogusTemp());
+ setTemp(1, LDefinition::BogusTemp());
+ setTemp(2, LDefinition::BogusTemp());
+ setTemp(3, valueTemp);
+ setTemp(4, offsetTemp);
+ setTemp(5, maskTemp);
+ }
+ const LAllocation* ptr() { return getOperand(0); }
+ const LAllocation* value() {
+ MOZ_ASSERT(valueOp == 1);
+ return getOperand(1);
+ }
+ const LAllocation* memoryBase() { return getOperand(2); }
+ const LDefinition* temp() { return getTemp(0); }
+
+ // Temp that may be used on some platforms to hold a computed address.
+ const LDefinition* addrTemp() { return getTemp(1); }
+ void setAddrTemp(const LDefinition& addrTemp) { setTemp(1, addrTemp); }
+
+ // Temp that may be used on LL/SC platforms for the flag result of the store.
+ const LDefinition* flagTemp() { return getTemp(2); }
+ // Temp that may be used on LL/SC platforms for extract/insert bits of word.
+ const LDefinition* valueTemp() { return getTemp(3); }
+ const LDefinition* offsetTemp() { return getTemp(4); }
+ const LDefinition* maskTemp() { return getTemp(5); }
+
+ MWasmAtomicBinopHeap* mir() const { return mir_->toWasmAtomicBinopHeap(); }
+};
+
+// Atomic binary operation where the result is discarded.
+class LWasmAtomicBinopHeapForEffect : public LInstructionHelper<0, 3, 5> {
+ public:
+ LIR_HEADER(WasmAtomicBinopHeapForEffect);
+ // ARM, ARM64, x86, x64
+ LWasmAtomicBinopHeapForEffect(
+ const LAllocation& ptr, const LAllocation& value,
+ const LDefinition& flagTemp = LDefinition::BogusTemp(),
+ const LAllocation& memoryBase = LAllocation())
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, ptr);
+ setOperand(1, value);
+ setOperand(2, memoryBase);
+ setTemp(0, LDefinition::BogusTemp());
+ setTemp(1, flagTemp);
+ }
+ // MIPS32, MIPS64
+ LWasmAtomicBinopHeapForEffect(const LAllocation& ptr,
+ const LAllocation& value,
+ const LDefinition& valueTemp,
+ const LDefinition& offsetTemp,
+ const LDefinition& maskTemp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, ptr);
+ setOperand(1, value);
+ setOperand(2, LAllocation());
+ setTemp(0, LDefinition::BogusTemp());
+ setTemp(1, LDefinition::BogusTemp());
+ setTemp(2, valueTemp);
+ setTemp(3, offsetTemp);
+ setTemp(4, maskTemp);
+ }
+ const LAllocation* ptr() { return getOperand(0); }
+ const LAllocation* value() { return getOperand(1); }
+ const LAllocation* memoryBase() { return getOperand(2); }
+
+ // Temp that may be used on some platforms to hold a computed address.
+ const LDefinition* addrTemp() { return getTemp(0); }
+ void setAddrTemp(const LDefinition& addrTemp) { setTemp(0, addrTemp); }
+
+ // Temp that may be used on LL/SC platforms for the flag result of the store.
+ const LDefinition* flagTemp() { return getTemp(1); }
+ // Temp that may be used on LL/SC platforms for extract/insert bits of word.
+ const LDefinition* valueTemp() { return getTemp(2); }
+ const LDefinition* offsetTemp() { return getTemp(3); }
+ const LDefinition* maskTemp() { return getTemp(4); }
+
+ MWasmAtomicBinopHeap* mir() const { return mir_->toWasmAtomicBinopHeap(); }
+};
+
+class LWasmDerivedPointer : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(WasmDerivedPointer);
+ explicit LWasmDerivedPointer(const LAllocation& base)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, base);
+ }
+ const LAllocation* base() { return getOperand(0); }
+ uint32_t offset() { return mirRaw()->toWasmDerivedPointer()->offset(); }
+};
+
+class LWasmDerivedIndexPointer : public LInstructionHelper<1, 2, 0> {
+ public:
+ LIR_HEADER(WasmDerivedIndexPointer);
+ explicit LWasmDerivedIndexPointer(const LAllocation& base,
+ const LAllocation& index)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, base);
+ setOperand(1, index);
+ }
+ const LAllocation* base() { return getOperand(0); }
+ const LAllocation* index() { return getOperand(1); }
+ Scale scale() { return mirRaw()->toWasmDerivedIndexPointer()->scale(); }
+};
+
+class LWasmParameterI64 : public LInstructionHelper<INT64_PIECES, 0, 0> {
+ public:
+ LIR_HEADER(WasmParameterI64);
+
+ LWasmParameterI64() : LInstructionHelper(classOpcode) {}
+};
+
+// This is used only with LWasmCall.
+class LWasmCallIndirectAdjunctSafepoint : public LInstructionHelper<0, 0, 0> {
+ CodeOffset offs_;
+ uint32_t framePushedAtStackMapBase_;
+
+ public:
+ LIR_HEADER(WasmCallIndirectAdjunctSafepoint);
+
+ LWasmCallIndirectAdjunctSafepoint()
+ : LInstructionHelper(classOpcode),
+ offs_(0),
+ framePushedAtStackMapBase_(0) {}
+
+ CodeOffset safepointLocation() const {
+ MOZ_ASSERT(offs_.offset() != 0);
+ return offs_;
+ }
+ uint32_t framePushedAtStackMapBase() const {
+ MOZ_ASSERT(offs_.offset() != 0);
+ return framePushedAtStackMapBase_;
+ }
+ void recordSafepointInfo(CodeOffset offs, uint32_t framePushed) {
+ offs_ = offs;
+ framePushedAtStackMapBase_ = framePushed;
+ }
+};
+
+// LWasmCall may be generated into two function calls in the case of
+// call_indirect, one for the fast path and one for the slow path. In that
+// case, the node carries a pointer to a companion node, the "adjunct
+// safepoint", representing the safepoint for the second of the two calls. The
+// dual-call construction is only meaningful for wasm because wasm has no
+// invalidation of code; this is not a pattern to be used generally.
+class LWasmCall : public LVariadicInstruction<0, 0> {
+ bool needsBoundsCheck_;
+ mozilla::Maybe<uint32_t> tableSize_;
+ LWasmCallIndirectAdjunctSafepoint* adjunctSafepoint_;
+
+ public:
+ LIR_HEADER(WasmCall);
+
+ LWasmCall(uint32_t numOperands, bool needsBoundsCheck,
+ mozilla::Maybe<uint32_t> tableSize = mozilla::Nothing())
+ : LVariadicInstruction(classOpcode, numOperands),
+ needsBoundsCheck_(needsBoundsCheck),
+ tableSize_(tableSize),
+ adjunctSafepoint_(nullptr) {
+ this->setIsCall();
+ }
+
+ MWasmCallBase* callBase() const {
+ if (isCatchable()) {
+ return static_cast<MWasmCallBase*>(mirCatchable());
+ }
+ return static_cast<MWasmCallBase*>(mirUncatchable());
+ }
+ bool isCatchable() const { return mir_->isWasmCallCatchable(); }
+ MWasmCallCatchable* mirCatchable() const {
+ return mir_->toWasmCallCatchable();
+ }
+ MWasmCallUncatchable* mirUncatchable() const {
+ return mir_->toWasmCallUncatchable();
+ }
+
+ static bool isCallPreserved(AnyRegister reg) {
+ // All MWasmCalls preserve the TLS register:
+ // - internal/indirect calls do by the internal wasm ABI
+ // - import calls do by explicitly saving/restoring at the callsite
+ // - builtin calls do because the TLS reg is non-volatile
+ // See also CodeGeneratorShared::emitWasmCall.
+ //
+ // All other registers are not preserved. This is is relied upon by
+ // MWasmCallCatchable which needs all live registers to be spilled before
+ // a call.
+ return !reg.isFloat() && reg.gpr() == InstanceReg;
+ }
+
+ bool needsBoundsCheck() const { return needsBoundsCheck_; }
+ mozilla::Maybe<uint32_t> tableSize() const { return tableSize_; }
+ LWasmCallIndirectAdjunctSafepoint* adjunctSafepoint() const {
+ MOZ_ASSERT(adjunctSafepoint_ != nullptr);
+ return adjunctSafepoint_;
+ }
+ void setAdjunctSafepoint(LWasmCallIndirectAdjunctSafepoint* asp) {
+ adjunctSafepoint_ = asp;
+ }
+};
+
+class LWasmRegisterResult : public LInstructionHelper<1, 0, 0> {
+ public:
+ LIR_HEADER(WasmRegisterResult);
+
+ LWasmRegisterResult() : LInstructionHelper(classOpcode) {}
+
+ MWasmRegisterResult* mir() const {
+ if (!mir_->isWasmRegisterResult()) {
+ return nullptr;
+ }
+ return mir_->toWasmRegisterResult();
+ }
+};
+
+class LWasmRegisterPairResult : public LInstructionHelper<2, 0, 0> {
+ public:
+ LIR_HEADER(WasmRegisterPairResult);
+
+ LWasmRegisterPairResult() : LInstructionHelper(classOpcode) {}
+
+ MDefinition* mir() const { return mirRaw(); }
+};
+
+inline uint32_t LStackArea::base() const {
+ return ins()->toWasmStackResultArea()->mir()->base();
+}
+inline void LStackArea::setBase(uint32_t base) {
+ ins()->toWasmStackResultArea()->mir()->setBase(base);
+}
+inline uint32_t LStackArea::size() const {
+ return ins()->toWasmStackResultArea()->mir()->byteSize();
+}
+
+inline bool LStackArea::ResultIterator::done() const {
+ return idx_ == alloc_.ins()->toWasmStackResultArea()->mir()->resultCount();
+}
+inline void LStackArea::ResultIterator::next() {
+ MOZ_ASSERT(!done());
+ idx_++;
+}
+inline LAllocation LStackArea::ResultIterator::alloc() const {
+ MOZ_ASSERT(!done());
+ MWasmStackResultArea* area = alloc_.ins()->toWasmStackResultArea()->mir();
+ return LStackSlot(area->base() - area->result(idx_).offset());
+}
+inline bool LStackArea::ResultIterator::isGcPointer() const {
+ MOZ_ASSERT(!done());
+ MWasmStackResultArea* area = alloc_.ins()->toWasmStackResultArea()->mir();
+ MIRType type = area->result(idx_).type();
+#ifndef JS_PUNBOX64
+ // LDefinition::TypeFrom isn't defined for MIRType::Int64 values on
+ // this platform, so here we have a special case.
+ if (type == MIRType::Int64) {
+ return false;
+ }
+#endif
+ return LDefinition::TypeFrom(type) == LDefinition::OBJECT;
+}
+
+class LWasmStackResult : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(WasmStackResult);
+
+ LWasmStackResult() : LInstructionHelper(classOpcode) {}
+
+ MWasmStackResult* mir() const { return mir_->toWasmStackResult(); }
+ LStackSlot result(uint32_t base) const {
+ return LStackSlot(base - mir()->result().offset());
+ }
+};
+
+class LWasmStackResult64 : public LInstructionHelper<INT64_PIECES, 1, 0> {
+ public:
+ LIR_HEADER(WasmStackResult64);
+
+ LWasmStackResult64() : LInstructionHelper(classOpcode) {}
+
+ MWasmStackResult* mir() const { return mir_->toWasmStackResult(); }
+ LStackSlot result(uint32_t base, LDefinition* def) {
+ uint32_t offset = base - mir()->result().offset();
+#if defined(JS_NUNBOX32)
+ if (def == getDef(INT64LOW_INDEX)) {
+ offset -= INT64LOW_OFFSET;
+ } else {
+ MOZ_ASSERT(def == getDef(INT64HIGH_INDEX));
+ offset -= INT64HIGH_OFFSET;
+ }
+#else
+ MOZ_ASSERT(def == getDef(0));
+#endif
+ return LStackSlot(offset);
+ }
+};
+
+inline LStackSlot LStackArea::resultAlloc(LInstruction* lir,
+ LDefinition* def) const {
+ if (lir->isWasmStackResult64()) {
+ return lir->toWasmStackResult64()->result(base(), def);
+ }
+ MOZ_ASSERT(def == lir->getDef(0));
+ return lir->toWasmStackResult()->result(base());
+}
+
+inline bool LNode::isCallPreserved(AnyRegister reg) const {
+ return isWasmCall() && LWasmCall::isCallPreserved(reg);
+}
+
+class LAssertRangeI : public LInstructionHelper<0, 1, 0> {
+ public:
+ LIR_HEADER(AssertRangeI)
+
+ explicit LAssertRangeI(const LAllocation& input)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, input);
+ }
+
+ const LAllocation* input() { return getOperand(0); }
+
+ MAssertRange* mir() { return mir_->toAssertRange(); }
+ const Range* range() { return mir()->assertedRange(); }
+};
+
+class LAssertRangeD : public LInstructionHelper<0, 1, 1> {
+ public:
+ LIR_HEADER(AssertRangeD)
+
+ LAssertRangeD(const LAllocation& input, const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, input);
+ setTemp(0, temp);
+ }
+
+ const LAllocation* input() { return getOperand(0); }
+
+ const LDefinition* temp() { return getTemp(0); }
+
+ MAssertRange* mir() { return mir_->toAssertRange(); }
+ const Range* range() { return mir()->assertedRange(); }
+};
+
+class LAssertRangeF : public LInstructionHelper<0, 1, 2> {
+ public:
+ LIR_HEADER(AssertRangeF)
+ LAssertRangeF(const LAllocation& input, const LDefinition& temp,
+ const LDefinition& temp2)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, input);
+ setTemp(0, temp);
+ setTemp(1, temp2);
+ }
+
+ const LAllocation* input() { return getOperand(0); }
+ const LDefinition* temp() { return getTemp(0); }
+ const LDefinition* temp2() { return getTemp(1); }
+
+ MAssertRange* mir() { return mir_->toAssertRange(); }
+ const Range* range() { return mir()->assertedRange(); }
+};
+
+class LAssertRangeV : public LInstructionHelper<0, BOX_PIECES, 3> {
+ public:
+ LIR_HEADER(AssertRangeV)
+
+ LAssertRangeV(const LBoxAllocation& input, const LDefinition& temp,
+ const LDefinition& floatTemp1, const LDefinition& floatTemp2)
+ : LInstructionHelper(classOpcode) {
+ setBoxOperand(Input, input);
+ setTemp(0, temp);
+ setTemp(1, floatTemp1);
+ setTemp(2, floatTemp2);
+ }
+
+ static const size_t Input = 0;
+
+ const LDefinition* temp() { return getTemp(0); }
+ const LDefinition* floatTemp1() { return getTemp(1); }
+ const LDefinition* floatTemp2() { return getTemp(2); }
+
+ MAssertRange* mir() { return mir_->toAssertRange(); }
+ const Range* range() { return mir()->assertedRange(); }
+};
+
+class LMemoryBarrier : public LInstructionHelper<0, 0, 0> {
+ private:
+ const MemoryBarrierBits type_;
+
+ public:
+ LIR_HEADER(MemoryBarrier)
+
+ // The parameter 'type' is a bitwise 'or' of the barrier types needed,
+ // see AtomicOp.h.
+ explicit LMemoryBarrier(MemoryBarrierBits type)
+ : LInstructionHelper(classOpcode), type_(type) {
+ MOZ_ASSERT((type_ & ~MembarAllbits) == MembarNobits);
+ }
+
+ MemoryBarrierBits type() const { return type_; }
+};
+
+// Math.random().
+class LRandom : public LInstructionHelper<1, 0, 1 + 2 * INT64_PIECES> {
+ public:
+ LIR_HEADER(Random)
+ LRandom(const LDefinition& temp0, const LInt64Definition& temp1,
+ const LInt64Definition& temp2)
+ : LInstructionHelper(classOpcode) {
+ setTemp(0, temp0);
+ setInt64Temp(1, temp1);
+ setInt64Temp(1 + INT64_PIECES, temp2);
+ }
+ const LDefinition* temp0() { return getTemp(0); }
+ LInt64Definition temp1() { return getInt64Temp(1); }
+ LInt64Definition temp2() { return getInt64Temp(1 + INT64_PIECES); }
+
+ MRandom* mir() const { return mir_->toRandom(); }
+};
+
+class LBigIntAsIntN64 : public LInstructionHelper<1, 1, 1 + INT64_PIECES> {
+ public:
+ LIR_HEADER(BigIntAsIntN64)
+
+ LBigIntAsIntN64(const LAllocation& input, const LDefinition& temp,
+ const LInt64Definition& temp64)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, input);
+ setTemp(0, temp);
+ setInt64Temp(1, temp64);
+ }
+
+ const LAllocation* input() { return getOperand(0); }
+ const LDefinition* temp() { return getTemp(0); }
+ LInt64Definition temp64() { return getInt64Temp(1); }
+};
+
+class LBigIntAsIntN32 : public LInstructionHelper<1, 1, 1 + INT64_PIECES> {
+ public:
+ LIR_HEADER(BigIntAsIntN32)
+
+ LBigIntAsIntN32(const LAllocation& input, const LDefinition& temp,
+ const LInt64Definition& temp64)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, input);
+ setTemp(0, temp);
+ setInt64Temp(1, temp64);
+ }
+
+ const LAllocation* input() { return getOperand(0); }
+ const LDefinition* temp() { return getTemp(0); }
+ LInt64Definition temp64() { return getInt64Temp(1); }
+};
+
+class LBigIntAsUintN64 : public LInstructionHelper<1, 1, 1 + INT64_PIECES> {
+ public:
+ LIR_HEADER(BigIntAsUintN64)
+
+ LBigIntAsUintN64(const LAllocation& input, const LDefinition& temp,
+ const LInt64Definition& temp64)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, input);
+ setTemp(0, temp);
+ setInt64Temp(1, temp64);
+ }
+
+ const LAllocation* input() { return getOperand(0); }
+ const LDefinition* temp() { return getTemp(0); }
+ LInt64Definition temp64() { return getInt64Temp(1); }
+};
+
+class LBigIntAsUintN32 : public LInstructionHelper<1, 1, 1 + INT64_PIECES> {
+ public:
+ LIR_HEADER(BigIntAsUintN32)
+
+ LBigIntAsUintN32(const LAllocation& input, const LDefinition& temp,
+ const LInt64Definition& temp64)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, input);
+ setTemp(0, temp);
+ setInt64Temp(1, temp64);
+ }
+
+ const LAllocation* input() { return getOperand(0); }
+ const LDefinition* temp() { return getTemp(0); }
+ LInt64Definition temp64() { return getInt64Temp(1); }
+};
+
+template <size_t NumDefs>
+class LIonToWasmCallBase : public LVariadicInstruction<NumDefs, 1> {
+ using Base = LVariadicInstruction<NumDefs, 1>;
+
+ public:
+ explicit LIonToWasmCallBase(LNode::Opcode classOpcode, uint32_t numOperands,
+ const LDefinition& temp)
+ : Base(classOpcode, numOperands) {
+ this->setIsCall();
+ this->setTemp(0, temp);
+ }
+ MIonToWasmCall* mir() const { return this->mir_->toIonToWasmCall(); }
+ const LDefinition* temp() { return this->getTemp(0); }
+};
+
+class LIonToWasmCall : public LIonToWasmCallBase<1> {
+ public:
+ LIR_HEADER(IonToWasmCall);
+ LIonToWasmCall(uint32_t numOperands, const LDefinition& temp)
+ : LIonToWasmCallBase<1>(classOpcode, numOperands, temp) {}
+};
+
+class LIonToWasmCallV : public LIonToWasmCallBase<BOX_PIECES> {
+ public:
+ LIR_HEADER(IonToWasmCallV);
+ LIonToWasmCallV(uint32_t numOperands, const LDefinition& temp)
+ : LIonToWasmCallBase<BOX_PIECES>(classOpcode, numOperands, temp) {}
+};
+
+class LIonToWasmCallI64 : public LIonToWasmCallBase<INT64_PIECES> {
+ public:
+ LIR_HEADER(IonToWasmCallI64);
+ LIonToWasmCallI64(uint32_t numOperands, const LDefinition& temp)
+ : LIonToWasmCallBase<INT64_PIECES>(classOpcode, numOperands, temp) {}
+};
+
+class LWasmGcObjectIsSubtypeOfAbstractAndBranch
+ : public LControlInstructionHelper<2, 2, 2> {
+ wasm::RefType sourceType_;
+ wasm::RefType destType_;
+
+ public:
+ LIR_HEADER(WasmGcObjectIsSubtypeOfAbstractAndBranch)
+
+ static constexpr uint32_t Object = 0;
+
+ LWasmGcObjectIsSubtypeOfAbstractAndBranch(MBasicBlock* ifTrue,
+ MBasicBlock* ifFalse,
+ wasm::RefType sourceType,
+ wasm::RefType destType,
+ const LAllocation& object,
+ const LDefinition& temp0)
+ : LControlInstructionHelper(classOpcode),
+ sourceType_(sourceType),
+ destType_(destType) {
+ setSuccessor(0, ifTrue);
+ setSuccessor(1, ifFalse);
+ setOperand(Object, object);
+ setTemp(0, temp0);
+ }
+
+ wasm::RefType sourceType() const { return sourceType_; }
+ wasm::RefType destType() const { return destType_; }
+
+ MBasicBlock* ifTrue() const { return getSuccessor(0); }
+ MBasicBlock* ifFalse() const { return getSuccessor(1); }
+
+ const LAllocation* object() { return getOperand(Object); }
+ const LDefinition* temp0() { return getTemp(0); }
+};
+
+class LWasmGcObjectIsSubtypeOfConcreteAndBranch
+ : public LControlInstructionHelper<2, 2, 2> {
+ wasm::RefType sourceType_;
+ wasm::RefType destType_;
+
+ public:
+ LIR_HEADER(WasmGcObjectIsSubtypeOfConcreteAndBranch)
+
+ static constexpr uint32_t Object = 0;
+ static constexpr uint32_t SuperSuperTypeVector = 1;
+
+ LWasmGcObjectIsSubtypeOfConcreteAndBranch(
+ MBasicBlock* ifTrue, MBasicBlock* ifFalse, wasm::RefType sourceType,
+ wasm::RefType destType, const LAllocation& object,
+ const LAllocation& superSuperTypeVector, const LDefinition& temp0,
+ const LDefinition& temp1)
+ : LControlInstructionHelper(classOpcode),
+ sourceType_(sourceType),
+ destType_(destType) {
+ setSuccessor(0, ifTrue);
+ setSuccessor(1, ifFalse);
+ setOperand(Object, object);
+ setOperand(SuperSuperTypeVector, superSuperTypeVector);
+ setTemp(0, temp0);
+ setTemp(1, temp1);
+ }
+
+ wasm::RefType sourceType() const { return sourceType_; }
+ wasm::RefType destType() const { return destType_; }
+
+ MBasicBlock* ifTrue() const { return getSuccessor(0); }
+ MBasicBlock* ifFalse() const { return getSuccessor(1); }
+
+ const LAllocation* object() { return getOperand(Object); }
+ const LAllocation* superSuperTypeVector() {
+ return getOperand(SuperSuperTypeVector);
+ }
+ const LDefinition* temp0() { return getTemp(0); }
+ const LDefinition* temp1() { return getTemp(1); }
+};
+
+// Wasm SIMD.
+
+// (v128, v128, v128) -> v128 effect-free operation.
+// temp is FPR.
+class LWasmTernarySimd128 : public LInstructionHelper<1, 3, 1> {
+ wasm::SimdOp op_;
+
+ public:
+ LIR_HEADER(WasmTernarySimd128)
+
+ static constexpr uint32_t V0 = 0;
+ static constexpr uint32_t V1 = 1;
+ static constexpr uint32_t V2 = 2;
+
+ LWasmTernarySimd128(wasm::SimdOp op, const LAllocation& v0,
+ const LAllocation& v1, const LAllocation& v2)
+ : LInstructionHelper(classOpcode), op_(op) {
+ setOperand(V0, v0);
+ setOperand(V1, v1);
+ setOperand(V2, v2);
+ }
+
+ LWasmTernarySimd128(wasm::SimdOp op, const LAllocation& v0,
+ const LAllocation& v1, const LAllocation& v2,
+ const LDefinition& temp)
+ : LInstructionHelper(classOpcode), op_(op) {
+ setOperand(V0, v0);
+ setOperand(V1, v1);
+ setOperand(V2, v2);
+ setTemp(0, temp);
+ }
+
+ const LAllocation* v0() { return getOperand(V0); }
+ const LAllocation* v1() { return getOperand(V1); }
+ const LAllocation* v2() { return getOperand(V2); }
+ const LDefinition* temp() { return getTemp(0); }
+
+ wasm::SimdOp simdOp() const { return op_; }
+};
+
+// (v128, v128) -> v128 effect-free operations
+// lhs and dest are the same.
+// temps (if in use) are FPR.
+// The op may differ from the MIR node's op.
+class LWasmBinarySimd128 : public LInstructionHelper<1, 2, 2> {
+ wasm::SimdOp op_;
+
+ public:
+ LIR_HEADER(WasmBinarySimd128)
+
+ static constexpr uint32_t Lhs = 0;
+ static constexpr uint32_t LhsDest = 0;
+ static constexpr uint32_t Rhs = 1;
+
+ LWasmBinarySimd128(wasm::SimdOp op, const LAllocation& lhs,
+ const LAllocation& rhs, const LDefinition& temp0,
+ const LDefinition& temp1)
+ : LInstructionHelper(classOpcode), op_(op) {
+ setOperand(Lhs, lhs);
+ setOperand(Rhs, rhs);
+ setTemp(0, temp0);
+ setTemp(1, temp1);
+ }
+
+ const LAllocation* lhs() { return getOperand(Lhs); }
+ const LAllocation* lhsDest() { return getOperand(LhsDest); }
+ const LAllocation* rhs() { return getOperand(Rhs); }
+ wasm::SimdOp simdOp() const { return op_; }
+
+ static bool SpecializeForConstantRhs(wasm::SimdOp op);
+};
+
+class LWasmBinarySimd128WithConstant : public LInstructionHelper<1, 1, 1> {
+ SimdConstant rhs_;
+
+ public:
+ LIR_HEADER(WasmBinarySimd128WithConstant)
+
+ static constexpr uint32_t Lhs = 0;
+ static constexpr uint32_t LhsDest = 0;
+
+ LWasmBinarySimd128WithConstant(const LAllocation& lhs,
+ const SimdConstant& rhs,
+ const LDefinition& temp)
+ : LInstructionHelper(classOpcode), rhs_(rhs) {
+ setOperand(Lhs, lhs);
+ setTemp(0, temp);
+ }
+
+ const LAllocation* lhs() { return getOperand(Lhs); }
+ const LAllocation* lhsDest() { return getOperand(LhsDest); }
+ const SimdConstant& rhs() { return rhs_; }
+ wasm::SimdOp simdOp() const {
+ return mir_->toWasmBinarySimd128WithConstant()->simdOp();
+ }
+};
+
+// (v128, i32) -> v128 effect-free variable-width shift operations
+// lhs and dest are the same.
+// temp is an FPR (if in use).
+class LWasmVariableShiftSimd128 : public LInstructionHelper<1, 2, 1> {
+ public:
+ LIR_HEADER(WasmVariableShiftSimd128)
+
+ static constexpr uint32_t Lhs = 0;
+ static constexpr uint32_t LhsDest = 0;
+ static constexpr uint32_t Rhs = 1;
+
+ LWasmVariableShiftSimd128(const LAllocation& lhs, const LAllocation& rhs,
+ const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(Lhs, lhs);
+ setOperand(Rhs, rhs);
+ setTemp(0, temp);
+ }
+
+ const LAllocation* lhs() { return getOperand(Lhs); }
+ const LAllocation* lhsDest() { return getOperand(LhsDest); }
+ const LAllocation* rhs() { return getOperand(Rhs); }
+ wasm::SimdOp simdOp() const { return mir_->toWasmShiftSimd128()->simdOp(); }
+};
+
+// (v128, i32) -> v128 effect-free constant-width shift operations
+class LWasmConstantShiftSimd128 : public LInstructionHelper<1, 1, 0> {
+ int32_t shift_;
+
+ public:
+ LIR_HEADER(WasmConstantShiftSimd128)
+
+ static constexpr uint32_t Src = 0;
+
+ LWasmConstantShiftSimd128(const LAllocation& src, int32_t shift)
+ : LInstructionHelper(classOpcode), shift_(shift) {
+ setOperand(Src, src);
+ }
+
+ const LAllocation* src() { return getOperand(Src); }
+ int32_t shift() { return shift_; }
+ wasm::SimdOp simdOp() const { return mir_->toWasmShiftSimd128()->simdOp(); }
+};
+
+// (v128) -> v128 sign replication operation.
+class LWasmSignReplicationSimd128 : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(WasmSignReplicationSimd128)
+
+ static constexpr uint32_t Src = 0;
+
+ explicit LWasmSignReplicationSimd128(const LAllocation& src)
+ : LInstructionHelper(classOpcode) {
+ setOperand(Src, src);
+ }
+
+ const LAllocation* src() { return getOperand(Src); }
+ wasm::SimdOp simdOp() const { return mir_->toWasmShiftSimd128()->simdOp(); }
+};
+
+// (v128, v128, imm_simd) -> v128 effect-free operation.
+// temp is FPR (and always in use).
+class LWasmShuffleSimd128 : public LInstructionHelper<1, 2, 1> {
+ private:
+ SimdShuffleOp op_;
+ SimdConstant control_;
+
+ public:
+ LIR_HEADER(WasmShuffleSimd128)
+
+ static constexpr uint32_t Lhs = 0;
+ static constexpr uint32_t LhsDest = 0;
+ static constexpr uint32_t Rhs = 1;
+
+ LWasmShuffleSimd128(const LAllocation& lhs, const LAllocation& rhs,
+ const LDefinition& temp, SimdShuffleOp op,
+ SimdConstant control)
+ : LInstructionHelper(classOpcode), op_(op), control_(control) {
+ setOperand(Lhs, lhs);
+ setOperand(Rhs, rhs);
+ setTemp(0, temp);
+ }
+
+ const LAllocation* lhs() { return getOperand(Lhs); }
+ const LAllocation* lhsDest() { return getOperand(LhsDest); }
+ const LAllocation* rhs() { return getOperand(Rhs); }
+ const LDefinition* temp() { return getTemp(0); }
+ SimdShuffleOp op() { return op_; }
+ SimdConstant control() { return control_; }
+};
+
+// (v128, imm_simd) -> v128 effect-free operation.
+class LWasmPermuteSimd128 : public LInstructionHelper<1, 1, 0> {
+ private:
+ SimdPermuteOp op_;
+ SimdConstant control_;
+
+ public:
+ LIR_HEADER(WasmPermuteSimd128)
+
+ static constexpr uint32_t Src = 0;
+
+ LWasmPermuteSimd128(const LAllocation& src, SimdPermuteOp op,
+ SimdConstant control)
+ : LInstructionHelper(classOpcode), op_(op), control_(control) {
+ setOperand(Src, src);
+ }
+
+ const LAllocation* src() { return getOperand(Src); }
+ SimdPermuteOp op() { return op_; }
+ SimdConstant control() { return control_; }
+};
+
+class LWasmReplaceLaneSimd128 : public LInstructionHelper<1, 2, 0> {
+ public:
+ LIR_HEADER(WasmReplaceLaneSimd128)
+
+ static constexpr uint32_t Lhs = 0;
+ static constexpr uint32_t LhsDest = 0;
+ static constexpr uint32_t Rhs = 1;
+
+ LWasmReplaceLaneSimd128(const LAllocation& lhs, const LAllocation& rhs)
+ : LInstructionHelper(classOpcode) {
+ setOperand(Lhs, lhs);
+ setOperand(Rhs, rhs);
+ }
+
+ const LAllocation* lhs() { return getOperand(Lhs); }
+ const LAllocation* lhsDest() { return getOperand(LhsDest); }
+ const LAllocation* rhs() { return getOperand(Rhs); }
+ uint32_t laneIndex() const {
+ return mir_->toWasmReplaceLaneSimd128()->laneIndex();
+ }
+ wasm::SimdOp simdOp() const {
+ return mir_->toWasmReplaceLaneSimd128()->simdOp();
+ }
+};
+
+class LWasmReplaceInt64LaneSimd128
+ : public LInstructionHelper<1, INT64_PIECES + 1, 0> {
+ public:
+ LIR_HEADER(WasmReplaceInt64LaneSimd128)
+
+ static constexpr uint32_t Lhs = 0;
+ static constexpr uint32_t LhsDest = 0;
+ static constexpr uint32_t Rhs = 1;
+
+ LWasmReplaceInt64LaneSimd128(const LAllocation& lhs,
+ const LInt64Allocation& rhs)
+ : LInstructionHelper(classOpcode) {
+ setOperand(Lhs, lhs);
+ setInt64Operand(Rhs, rhs);
+ }
+
+ const LAllocation* lhs() { return getOperand(Lhs); }
+ const LAllocation* lhsDest() { return getOperand(LhsDest); }
+ const LInt64Allocation rhs() { return getInt64Operand(Rhs); }
+ const LDefinition* output() { return this->getDef(0); }
+ uint32_t laneIndex() const {
+ return mir_->toWasmReplaceLaneSimd128()->laneIndex();
+ }
+ wasm::SimdOp simdOp() const {
+ return mir_->toWasmReplaceLaneSimd128()->simdOp();
+ }
+};
+
+// (scalar) -> v128 effect-free operations, scalar != int64
+class LWasmScalarToSimd128 : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(WasmScalarToSimd128)
+
+ static constexpr uint32_t Src = 0;
+
+ explicit LWasmScalarToSimd128(const LAllocation& src)
+ : LInstructionHelper(classOpcode) {
+ setOperand(Src, src);
+ }
+
+ const LAllocation* src() { return getOperand(Src); }
+ wasm::SimdOp simdOp() const {
+ return mir_->toWasmScalarToSimd128()->simdOp();
+ }
+};
+
+// (int64) -> v128 effect-free operations
+class LWasmInt64ToSimd128 : public LInstructionHelper<1, INT64_PIECES, 0> {
+ public:
+ LIR_HEADER(WasmInt64ToSimd128)
+
+ static constexpr uint32_t Src = 0;
+
+ explicit LWasmInt64ToSimd128(const LInt64Allocation& src)
+ : LInstructionHelper(classOpcode) {
+ setInt64Operand(Src, src);
+ }
+
+ const LInt64Allocation src() { return getInt64Operand(Src); }
+ wasm::SimdOp simdOp() const {
+ return mir_->toWasmScalarToSimd128()->simdOp();
+ }
+};
+
+// (v128) -> v128 effect-free operations
+// temp is FPR (if in use).
+class LWasmUnarySimd128 : public LInstructionHelper<1, 1, 1> {
+ public:
+ LIR_HEADER(WasmUnarySimd128)
+
+ static constexpr uint32_t Src = 0;
+
+ LWasmUnarySimd128(const LAllocation& src, const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(Src, src);
+ setTemp(0, temp);
+ }
+
+ const LAllocation* src() { return getOperand(Src); }
+ const LDefinition* temp() { return getTemp(0); }
+ wasm::SimdOp simdOp() const { return mir_->toWasmUnarySimd128()->simdOp(); }
+};
+
+// (v128, imm) -> scalar effect-free operations.
+// temp is FPR (if in use).
+class LWasmReduceSimd128 : public LInstructionHelper<1, 1, 1> {
+ public:
+ LIR_HEADER(WasmReduceSimd128)
+
+ static constexpr uint32_t Src = 0;
+
+ explicit LWasmReduceSimd128(const LAllocation& src, const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(Src, src);
+ setTemp(0, temp);
+ }
+
+ const LAllocation* src() { return getOperand(Src); }
+ uint32_t imm() const { return mir_->toWasmReduceSimd128()->imm(); }
+ wasm::SimdOp simdOp() const { return mir_->toWasmReduceSimd128()->simdOp(); }
+};
+
+// (v128, onTrue, onFalse) test-and-branch operations.
+class LWasmReduceAndBranchSimd128 : public LControlInstructionHelper<2, 1, 0> {
+ wasm::SimdOp op_;
+
+ public:
+ LIR_HEADER(WasmReduceAndBranchSimd128)
+
+ static constexpr uint32_t Src = 0;
+ static constexpr uint32_t IfTrue = 0;
+ static constexpr uint32_t IfFalse = 1;
+
+ LWasmReduceAndBranchSimd128(const LAllocation& src, wasm::SimdOp op,
+ MBasicBlock* ifTrue, MBasicBlock* ifFalse)
+ : LControlInstructionHelper(classOpcode), op_(op) {
+ setOperand(Src, src);
+ setSuccessor(IfTrue, ifTrue);
+ setSuccessor(IfFalse, ifFalse);
+ }
+
+ const LAllocation* src() { return getOperand(Src); }
+ wasm::SimdOp simdOp() const { return op_; }
+ MBasicBlock* ifTrue() const { return getSuccessor(IfTrue); }
+ MBasicBlock* ifFalse() const { return getSuccessor(IfFalse); }
+};
+
+// (v128, imm) -> i64 effect-free operations
+class LWasmReduceSimd128ToInt64
+ : public LInstructionHelper<INT64_PIECES, 1, 0> {
+ public:
+ LIR_HEADER(WasmReduceSimd128ToInt64)
+
+ static constexpr uint32_t Src = 0;
+
+ explicit LWasmReduceSimd128ToInt64(const LAllocation& src)
+ : LInstructionHelper(classOpcode) {
+ setOperand(Src, src);
+ }
+
+ const LAllocation* src() { return getOperand(Src); }
+ uint32_t imm() const { return mir_->toWasmReduceSimd128()->imm(); }
+ wasm::SimdOp simdOp() const { return mir_->toWasmReduceSimd128()->simdOp(); }
+};
+
+class LWasmLoadLaneSimd128 : public LInstructionHelper<1, 3, 1> {
+ public:
+ LIR_HEADER(WasmLoadLaneSimd128);
+
+ static constexpr uint32_t Src = 2;
+
+ explicit LWasmLoadLaneSimd128(const LAllocation& ptr, const LAllocation& src,
+ const LDefinition& temp,
+ const LAllocation& memoryBase = LAllocation())
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, ptr);
+ setOperand(1, memoryBase);
+ setOperand(Src, src);
+ setTemp(0, temp);
+ }
+
+ const LAllocation* ptr() { return getOperand(0); }
+ const LAllocation* memoryBase() { return getOperand(1); }
+ const LAllocation* src() { return getOperand(Src); }
+ const LDefinition* temp() { return getTemp(0); }
+ MWasmLoadLaneSimd128* mir() const { return mir_->toWasmLoadLaneSimd128(); }
+ uint32_t laneSize() const {
+ return mir_->toWasmLoadLaneSimd128()->laneSize();
+ }
+ uint32_t laneIndex() const {
+ return mir_->toWasmLoadLaneSimd128()->laneIndex();
+ }
+};
+
+class LWasmStoreLaneSimd128 : public LInstructionHelper<1, 3, 1> {
+ public:
+ LIR_HEADER(WasmStoreLaneSimd128);
+
+ static constexpr uint32_t Src = 2;
+
+ explicit LWasmStoreLaneSimd128(const LAllocation& ptr, const LAllocation& src,
+ const LDefinition& temp,
+ const LAllocation& memoryBase = LAllocation())
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, ptr);
+ setOperand(1, memoryBase);
+ setOperand(Src, src);
+ setTemp(0, temp);
+ }
+
+ const LAllocation* ptr() { return getOperand(0); }
+ const LAllocation* memoryBase() { return getOperand(1); }
+ const LAllocation* src() { return getOperand(Src); }
+ const LDefinition* temp() { return getTemp(0); }
+ MWasmStoreLaneSimd128* mir() const { return mir_->toWasmStoreLaneSimd128(); }
+ uint32_t laneSize() const {
+ return mir_->toWasmStoreLaneSimd128()->laneSize();
+ }
+ uint32_t laneIndex() const {
+ return mir_->toWasmStoreLaneSimd128()->laneIndex();
+ }
+};
+
+// End Wasm SIMD
+
+// End Wasm Exception Handling
+
+} // namespace jit
+} // namespace js
+
+#endif /* jit_shared_LIR_shared_h */