diff options
author | Brian Smith <brian@dbsoft.org> | 2023-09-22 13:23:36 -0500 |
---|---|---|
committer | Moonchild <moonchild@palemoon.org> | 2023-09-25 10:46:25 +0200 |
commit | f96b1559881debb518ad5e27f1754363fd6280ed (patch) | |
tree | 48eb99e9451d69a45de7540c2f7b924bb8eec941 | |
parent | d5cc24e91620a621217210b292a2ec53d6c01f42 (diff) | |
download | uxp-f96b1559881debb518ad5e27f1754363fd6280ed.tar.gz |
Issue #2313 - Implement WebAssembly sign extension opcodes. (uplift)
37 files changed, 444 insertions, 49 deletions
diff --git a/js/src/jit-test/lib/wasm-binary.js b/js/src/jit-test/lib/wasm-binary.js index e57ac84914..3769386105 100644 --- a/js/src/jit-test/lib/wasm-binary.js +++ b/js/src/jit-test/lib/wasm-binary.js @@ -84,6 +84,8 @@ const I64TruncUF32Code = 0xaf; const I64TruncSF64Code = 0xb0; const I64TruncUF64Code = 0xb1; +const FirstInvalidOpcode = 0xc5; + // DefinitionKind const FunctionCode = 0x00; const TableCode = 0x01; diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index f2c3076f99..6562cbf554 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -12249,16 +12249,16 @@ CodeGenerator::visitRandom(LRandom* ins) } void -CodeGenerator::visitSignExtend(LSignExtend* ins) +CodeGenerator::visitSignExtendInt32(LSignExtendInt32* ins) { Register input = ToRegister(ins->input()); Register output = ToRegister(ins->output()); switch (ins->mode()) { - case MSignExtend::Byte: + case MSignExtendInt32::Byte: masm.move8SignExtend(input, output); break; - case MSignExtend::Half: + case MSignExtendInt32::Half: masm.move16SignExtend(input, output); break; } diff --git a/js/src/jit/CodeGenerator.h b/js/src/jit/CodeGenerator.h index ff68eebd19..ae873c4047 100644 --- a/js/src/jit/CodeGenerator.h +++ b/js/src/jit/CodeGenerator.h @@ -442,7 +442,7 @@ class CodeGenerator final : public CodeGeneratorSpecific void visitRotate(LRotate* ins); void visitRandom(LRandom* ins); - void visitSignExtend(LSignExtend* ins); + void visitSignExtendInt32(LSignExtendInt32* ins); void visitModuleMetadata(LModuleMetadata* lir); void visitDynamicImport(LDynamicImport* lir); diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp index 61c0c8350f..aca525260e 100644 --- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -1328,14 +1328,14 @@ LIRGenerator::visitUrsh(MUrsh* ins) } void -LIRGenerator::visitSignExtend(MSignExtend* ins) +LIRGenerator::visitSignExtendInt32(MSignExtendInt32* ins) { LInstructionHelper<1, 1, 0>* lir; - if (ins->mode() == MSignExtend::Byte) - lir = new(alloc()) LSignExtend(useByteOpRegisterAtStart(ins->input()), ins->mode()); + if (ins->mode() == MSignExtendInt32::Byte) + lir = new(alloc()) LSignExtendInt32(useByteOpRegisterAtStart(ins->input()), ins->mode()); else - lir = new(alloc()) LSignExtend(useRegisterAtStart(ins->input()), ins->mode()); + lir = new(alloc()) LSignExtendInt32(useRegisterAtStart(ins->input()), ins->mode()); define(lir, ins); } diff --git a/js/src/jit/Lowering.h b/js/src/jit/Lowering.h index e1fc611684..e92fe15fd3 100644 --- a/js/src/jit/Lowering.h +++ b/js/src/jit/Lowering.h @@ -130,7 +130,7 @@ class LIRGenerator : public LIRGeneratorSpecific void visitLsh(MLsh* ins); void visitRsh(MRsh* ins); void visitUrsh(MUrsh* ins); - void visitSignExtend(MSignExtend* ins); + void visitSignExtendInt32(MSignExtendInt32* ins); void visitRotate(MRotate* ins); void visitFloor(MFloor* ins); void visitCeil(MCeil* ins); diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp index a68e344011..d3c585cabf 100644 --- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -3142,9 +3142,9 @@ MRsh::foldsTo(TempAllocator& alloc) switch (shift) { case 16: - return MSignExtend::New(alloc, lhs->getOperand(0), MSignExtend::Half); + return MSignExtendInt32::New(alloc, lhs->getOperand(0), MSignExtendInt32::Half); case 24: - return MSignExtend::New(alloc, lhs->getOperand(0), MSignExtend::Byte); + return MSignExtendInt32::New(alloc, lhs->getOperand(0), MSignExtendInt32::Byte); } return this; @@ -4327,6 +4327,41 @@ MExtendInt32ToInt64::foldsTo(TempAllocator& alloc) } MDefinition* +MSignExtendInt32::foldsTo(TempAllocator& alloc) +{ + MDefinition* input = this->input(); + if (input->isConstant()) { + int32_t c = input->toConstant()->toInt32(); + int32_t res; + switch (mode_) { + case Byte: res = int32_t(int8_t(c & 0xFF)); break; + case Half: res = int32_t(int16_t(c & 0xFFFF)); break; + } + return MConstant::New(alloc, Int32Value(res)); + } + + return this; +} + +MDefinition* +MSignExtendInt64::foldsTo(TempAllocator& alloc) +{ + MDefinition* input = this->input(); + if (input->isConstant()) { + int64_t c = input->toConstant()->toInt64(); + int64_t res; + switch (mode_) { + case Byte: res = int64_t(int8_t(c & 0xFF)); break; + case Half: res = int64_t(int16_t(c & 0xFFFF)); break; + case Word: res = int64_t(int32_t(c & 0xFFFFFFFFU)); break; + } + return MConstant::NewInt64(alloc, res); + } + + return this; +} + +MDefinition* MToDouble::foldsTo(TempAllocator& alloc) { MDefinition* input = getOperand(0); diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index 5c854f6060..ec0b92efc2 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -6172,7 +6172,7 @@ class MUrsh : public MShiftInstruction ALLOW_CLONE(MUrsh) }; -class MSignExtend +class MSignExtendInt32 : public MUnaryInstruction, public NoTypePolicy::Data { @@ -6185,7 +6185,7 @@ class MSignExtend private: Mode mode_; - MSignExtend(MDefinition* op, Mode mode) + MSignExtendInt32(MDefinition* op, Mode mode) : MUnaryInstruction(op), mode_(mode) { setResultType(MIRType::Int32); @@ -6193,17 +6193,67 @@ class MSignExtend } public: - INSTRUCTION_HEADER(SignExtend) + INSTRUCTION_HEADER(SignExtendInt32) TRIVIAL_NEW_WRAPPERS - Mode mode() { return mode_; } + Mode mode() const { return mode_; } + + MDefinition* foldsTo(TempAllocator& alloc) override; + bool congruentTo(const MDefinition* ins) const override { + if (!congruentIfOperandsEqual(ins)) + return false; + return ins->isSignExtendInt32() && ins->toSignExtendInt32()->mode_ == mode_; + } + AliasSet getAliasSet() const override { + return AliasSet::None(); + } MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override; bool canRecoverOnBailout() const override { return true; } - ALLOW_CLONE(MSignExtend) + ALLOW_CLONE(MSignExtendInt32) +}; + +class MSignExtendInt64 + : public MUnaryInstruction, + public NoTypePolicy::Data +{ + public: + enum Mode { + Byte, + Half, + Word + }; + + private: + Mode mode_; + + MSignExtendInt64(MDefinition* op, Mode mode) + : MUnaryInstruction(op), mode_(mode) + { + setResultType(MIRType::Int64); + setMovable(); + } + + public: + INSTRUCTION_HEADER(SignExtendInt64) + TRIVIAL_NEW_WRAPPERS + + Mode mode() const { return mode_; } + + MDefinition* foldsTo(TempAllocator& alloc) override; + bool congruentTo(const MDefinition* ins) const override { + if (!congruentIfOperandsEqual(ins)) + return false; + return ins->isSignExtendInt64() && ins->toSignExtendInt64()->mode_ == mode_; + } + AliasSet getAliasSet() const override { + return AliasSet::None(); + } + + ALLOW_CLONE(MSignExtendInt64) }; class MBinaryArithInstruction diff --git a/js/src/jit/MOpcodes.h b/js/src/jit/MOpcodes.h index b580a3b7dd..77f6250658 100644 --- a/js/src/jit/MOpcodes.h +++ b/js/src/jit/MOpcodes.h @@ -87,7 +87,8 @@ namespace jit { _(Lsh) \ _(Rsh) \ _(Ursh) \ - _(SignExtend) \ + _(SignExtendInt32) \ + _(SignExtendInt64) \ _(MinMax) \ _(Abs) \ _(Clz) \ diff --git a/js/src/jit/Recover.cpp b/js/src/jit/Recover.cpp index 0d6882f52c..8754516ef4 100644 --- a/js/src/jit/Recover.cpp +++ b/js/src/jit/Recover.cpp @@ -336,32 +336,32 @@ RUrsh::recover(JSContext* cx, SnapshotIterator& iter) const } bool -MSignExtend::writeRecoverData(CompactBufferWriter& writer) const +MSignExtendInt32::writeRecoverData(CompactBufferWriter& writer) const { MOZ_ASSERT(canRecoverOnBailout()); - writer.writeUnsigned(uint32_t(RInstruction::Recover_SignExtend)); + writer.writeUnsigned(uint32_t(RInstruction::Recover_SignExtendInt32)); MOZ_ASSERT(Mode(uint8_t(mode_)) == mode_); writer.writeByte(uint8_t(mode_)); return true; } -RSignExtend::RSignExtend(CompactBufferReader& reader) +RSignExtendInt32::RSignExtendInt32(CompactBufferReader& reader) { mode_ = reader.readByte(); } bool -RSignExtend::recover(JSContext* cx, SnapshotIterator& iter) const +RSignExtendInt32::recover(JSContext* cx, SnapshotIterator& iter) const { RootedValue operand(cx, iter.read()); int32_t result; - switch (MSignExtend::Mode(mode_)) { - case MSignExtend::Byte: + switch (MSignExtendInt32::Mode(mode_)) { + case MSignExtendInt32::Byte: if (!js::SignExtendOperation<int8_t>(cx, operand, &result)) return false; break; - case MSignExtend::Half: + case MSignExtendInt32::Half: if (!js::SignExtendOperation<int16_t>(cx, operand, &result)) return false; break; diff --git a/js/src/jit/Recover.h b/js/src/jit/Recover.h index 41e64a9259..1dfeaa0d0c 100644 --- a/js/src/jit/Recover.h +++ b/js/src/jit/Recover.h @@ -64,7 +64,7 @@ namespace jit { _(Lsh) \ _(Rsh) \ _(Ursh) \ - _(SignExtend) \ + _(SignExtendInt32) \ _(Add) \ _(Sub) \ _(Mul) \ @@ -255,13 +255,13 @@ class RUrsh final : public RInstruction MOZ_MUST_USE bool recover(JSContext* cx, SnapshotIterator& iter) const override; }; -class RSignExtend final : public RInstruction +class RSignExtendInt32 final : public RInstruction { private: uint8_t mode_; public: - RINSTRUCTION_HEADER_NUM_OP_(SignExtend, 1) + RINSTRUCTION_HEADER_NUM_OP_(SignExtendInt32, 1) MOZ_MUST_USE bool recover(JSContext* cx, SnapshotIterator& iter) const override; }; diff --git a/js/src/jit/arm/CodeGenerator-arm.cpp b/js/src/jit/arm/CodeGenerator-arm.cpp index 93ef58a3ab..25ed23a2c8 100644 --- a/js/src/jit/arm/CodeGenerator-arm.cpp +++ b/js/src/jit/arm/CodeGenerator-arm.cpp @@ -3365,6 +3365,24 @@ CodeGeneratorARM::visitExtendInt32ToInt64(LExtendInt32ToInt64* lir) } void +CodeGeneratorARM::visitSignExtendInt64(LSignExtendInt64* lir) +{ + Register64 input = ToRegister64(lir->getInt64Operand(0)); + Register64 output = ToOutRegister64(lir); + switch (lir->mode()) { + case MSignExtendInt64::Byte: + masm.move8SignExtend(input.low, output.low); + break; + case MSignExtendInt64::Half: + masm.move16SignExtend(input.low, output.low); + break; + case MSignExtendInt64::Word: + break; + } + masm.ma_asr(Imm32(31), output.low, output.high); +} + +void CodeGeneratorARM::visitDivOrModI64(LDivOrModI64* lir) { Register64 lhs = ToRegister64(lir->getInt64Operand(LDivOrModI64::Lhs)); diff --git a/js/src/jit/arm/CodeGenerator-arm.h b/js/src/jit/arm/CodeGenerator-arm.h index 126c77649a..02fc40cb26 100644 --- a/js/src/jit/arm/CodeGenerator-arm.h +++ b/js/src/jit/arm/CodeGenerator-arm.h @@ -168,6 +168,7 @@ class CodeGeneratorARM : public CodeGeneratorShared virtual void visitWrapInt64ToInt32(LWrapInt64ToInt32* lir); virtual void visitExtendInt32ToInt64(LExtendInt32ToInt64* lir); + virtual void visitSignExtendInt64(LSignExtendInt64* ins); virtual void visitAddI64(LAddI64* lir); virtual void visitSubI64(LSubI64* lir); virtual void visitMulI64(LMulI64* lir); diff --git a/js/src/jit/arm/Lowering-arm.cpp b/js/src/jit/arm/Lowering-arm.cpp index bb25d81e68..22bf3bc668 100644 --- a/js/src/jit/arm/Lowering-arm.cpp +++ b/js/src/jit/arm/Lowering-arm.cpp @@ -1028,3 +1028,9 @@ LIRGeneratorARM::visitExtendInt32ToInt64(MExtendInt32ToInt64* ins) lir->setDef(0, def); } + +void +LIRGeneratorARM::visitSignExtendInt64(MSignExtendInt64* ins) +{ + defineInt64(new(alloc()) LSignExtendInt64(useInt64RegisterAtStart(ins->input())), ins); +} diff --git a/js/src/jit/arm/Lowering-arm.h b/js/src/jit/arm/Lowering-arm.h index 137ab32d2a..14b824333b 100644 --- a/js/src/jit/arm/Lowering-arm.h +++ b/js/src/jit/arm/Lowering-arm.h @@ -121,6 +121,7 @@ class LIRGeneratorARM : public LIRGeneratorShared void visitInt64ToFloatingPoint(MInt64ToFloatingPoint* ins); void visitCopySign(MCopySign* ins); void visitExtendInt32ToInt64(MExtendInt32ToInt64* ins); + void visitSignExtendInt64(MSignExtendInt64* ins); }; typedef LIRGeneratorARM LIRGeneratorSpecific; diff --git a/js/src/jit/arm64/Lowering-arm64.cpp b/js/src/jit/arm64/Lowering-arm64.cpp index 97ca7b2a5b..59c6a6a255 100644 --- a/js/src/jit/arm64/Lowering-arm64.cpp +++ b/js/src/jit/arm64/Lowering-arm64.cpp @@ -366,3 +366,9 @@ LIRGeneratorARM64::visitExtendInt32ToInt64(MExtendInt32ToInt64* ins) { MOZ_CRASH("NYI"); } + +void +LIRGeneratorARM64::visitSignExtendInt64(MSignExtendInt64* ins) +{ + MOZ_CRASH("NYI"); +} diff --git a/js/src/jit/arm64/Lowering-arm64.h b/js/src/jit/arm64/Lowering-arm64.h index d9c3c49388..a81d9e8352 100644 --- a/js/src/jit/arm64/Lowering-arm64.h +++ b/js/src/jit/arm64/Lowering-arm64.h @@ -121,6 +121,7 @@ class LIRGeneratorARM64 : public LIRGeneratorShared void visitInt64ToFloatingPoint(MInt64ToFloatingPoint* ins); void visitCopySign(MCopySign* ins); void visitExtendInt32ToInt64(MExtendInt32ToInt64* ins); + void visitSignExtendInt64(MSignExtendInt64* ins); }; typedef LIRGeneratorARM64 LIRGeneratorSpecific; diff --git a/js/src/jit/none/Lowering-none.h b/js/src/jit/none/Lowering-none.h index 6a52ac36d8..5fa9c27042 100644 --- a/js/src/jit/none/Lowering-none.h +++ b/js/src/jit/none/Lowering-none.h @@ -107,6 +107,7 @@ class LIRGeneratorNone : public LIRGeneratorShared void visitWasmTruncateToInt64(MWasmTruncateToInt64*) { MOZ_CRASH(); } void visitInt64ToFloatingPoint(MInt64ToFloatingPoint*) { MOZ_CRASH(); } void visitExtendInt32ToInt64(MExtendInt32ToInt64* ins) { MOZ_CRASH(); } + void visitSignExtendInt64(MSignExtendInt64* ins) { MOZ_CRASH(); } }; typedef LIRGeneratorNone LIRGeneratorSpecific; diff --git a/js/src/jit/shared/LIR-shared.h b/js/src/jit/shared/LIR-shared.h index c0abfc9123..5d82c2ab05 100644 --- a/js/src/jit/shared/LIR-shared.h +++ b/js/src/jit/shared/LIR-shared.h @@ -3351,19 +3351,34 @@ class LShiftI64 : public LInstructionHelper<INT64_PIECES, INT64_PIECES + 1, 0> }; // Sign extension -class LSignExtend : public LInstructionHelper<1, 1, 0> +class LSignExtendInt32 : public LInstructionHelper<1, 1, 0> { - MSignExtend::Mode mode_; + MSignExtendInt32::Mode mode_; public: - LIR_HEADER(SignExtend); - explicit LSignExtend(const LAllocation& num, MSignExtend::Mode mode) + LIR_HEADER(SignExtendInt32); + explicit LSignExtendInt32(const LAllocation& num, MSignExtendInt32::Mode mode) : mode_(mode) { setOperand(0, num); } - MSignExtend::Mode mode() { return mode_; } + MSignExtendInt32::Mode mode() { return mode_; } +}; + +class LSignExtendInt64 : public LInstructionHelper<INT64_PIECES, INT64_PIECES, 0> +{ + public: + LIR_HEADER(SignExtendInt64) + explicit LSignExtendInt64(const LInt64Allocation& input) { + setInt64Operand(0, input); + } + + const MSignExtendInt64* mir() const { + return mir_->toSignExtendInt64(); + } + + MSignExtendInt64::Mode mode() const { return mir()->mode(); } }; class LUrshD : public LBinaryMath<1> diff --git a/js/src/jit/shared/LOpcodes-shared.h b/js/src/jit/shared/LOpcodes-shared.h index 92fcf16e7a..bdcc3f1bb6 100644 --- a/js/src/jit/shared/LOpcodes-shared.h +++ b/js/src/jit/shared/LOpcodes-shared.h @@ -111,7 +111,8 @@ _(BitOpV) \ _(ShiftI) \ _(ShiftI64) \ - _(SignExtend) \ + _(SignExtendInt32) \ + _(SignExtendInt64) \ _(UrshD) \ _(Return) \ _(Throw) \ diff --git a/js/src/jit/x64/Assembler-x64.h b/js/src/jit/x64/Assembler-x64.h index 509b5b5450..65777d64b9 100644 --- a/js/src/jit/x64/Assembler-x64.h +++ b/js/src/jit/x64/Assembler-x64.h @@ -470,6 +470,9 @@ class Assembler : public AssemblerX86Shared void movsbq(const Operand& src, Register dest) { switch (src.kind()) { + case Operand::REG: + masm.movsbq_rr(src.reg(), dest.encoding()); + break; case Operand::MEM_REG_DISP: masm.movsbq_mr(src.disp(), src.base(), dest.encoding()); break; @@ -489,6 +492,9 @@ class Assembler : public AssemblerX86Shared void movswq(const Operand& src, Register dest) { switch (src.kind()) { + case Operand::REG: + masm.movswq_rr(src.reg(), dest.encoding()); + break; case Operand::MEM_REG_DISP: masm.movswq_mr(src.disp(), src.base(), dest.encoding()); break; diff --git a/js/src/jit/x64/BaseAssembler-x64.h b/js/src/jit/x64/BaseAssembler-x64.h index bf9ca9f5cb..f66cecf35d 100644 --- a/js/src/jit/x64/BaseAssembler-x64.h +++ b/js/src/jit/x64/BaseAssembler-x64.h @@ -652,6 +652,11 @@ class BaseAssemblerX64 : public BaseAssembler m_formatter.immediate64(imm); } + void movsbq_rr(RegisterID src, RegisterID dst) + { + spew("movsbq %s, %s", GPReg32Name(src), GPReg64Name(dst)); + m_formatter.twoByteOp64(OP2_MOVSX_GvEb, src, dst); + } void movsbq_mr(int32_t offset, RegisterID base, RegisterID dst) { spew("movsbq " MEM_ob ", %s", ADDR_ob(offset, base), GPReg64Name(dst)); @@ -663,6 +668,11 @@ class BaseAssemblerX64 : public BaseAssembler m_formatter.twoByteOp64(OP2_MOVSX_GvEb, offset, base, index, scale, dst); } + void movswq_rr(RegisterID src, RegisterID dst) + { + spew("movswq %s, %s", GPReg32Name(src), GPReg64Name(dst)); + m_formatter.twoByteOp64(OP2_MOVSX_GvEw, src, dst); + } void movswq_mr(int32_t offset, RegisterID base, RegisterID dst) { spew("movswq " MEM_ob ", %s", ADDR_ob(offset, base), GPReg64Name(dst)); diff --git a/js/src/jit/x64/CodeGenerator-x64.cpp b/js/src/jit/x64/CodeGenerator-x64.cpp index 3f4052f51d..8f4ef6e70d 100644 --- a/js/src/jit/x64/CodeGenerator-x64.cpp +++ b/js/src/jit/x64/CodeGenerator-x64.cpp @@ -803,6 +803,24 @@ CodeGeneratorX64::visitExtendInt32ToInt64(LExtendInt32ToInt64* lir) } void +CodeGeneratorX64::visitSignExtendInt64(LSignExtendInt64* ins) +{ + Register64 input = ToRegister64(ins->getInt64Operand(0)); + Register64 output = ToOutRegister64(ins); + switch (ins->mode()) { + case MSignExtendInt64::Byte: + masm.movsbq(Operand(input.reg), output.reg); + break; + case MSignExtendInt64::Half: + masm.movswq(Operand(input.reg), output.reg); + break; + case MSignExtendInt64::Word: + masm.movslq(Operand(input.reg), output.reg); + break; + } +} + +void CodeGeneratorX64::visitWasmTruncateToInt64(LWasmTruncateToInt64* lir) { FloatRegister input = ToFloatRegister(lir->input()); diff --git a/js/src/jit/x64/CodeGenerator-x64.h b/js/src/jit/x64/CodeGenerator-x64.h index 3c4ff88d6b..2bb3b389b4 100644 --- a/js/src/jit/x64/CodeGenerator-x64.h +++ b/js/src/jit/x64/CodeGenerator-x64.h @@ -52,6 +52,7 @@ class CodeGeneratorX64 : public CodeGeneratorX86Shared void visitTruncateFToInt32(LTruncateFToInt32* ins); void visitWrapInt64ToInt32(LWrapInt64ToInt32* lir); void visitExtendInt32ToInt64(LExtendInt32ToInt64* lir); + void visitSignExtendInt64(LSignExtendInt64* ins); void visitWasmTruncateToInt64(LWasmTruncateToInt64* lir); void visitInt64ToFloatingPoint(LInt64ToFloatingPoint* lir); void visitLoadTypedArrayElementStatic(LLoadTypedArrayElementStatic* ins); diff --git a/js/src/jit/x64/Lowering-x64.cpp b/js/src/jit/x64/Lowering-x64.cpp index 4aebe05af2..79c210aa1d 100644 --- a/js/src/jit/x64/Lowering-x64.cpp +++ b/js/src/jit/x64/Lowering-x64.cpp @@ -494,3 +494,10 @@ LIRGeneratorX64::visitExtendInt32ToInt64(MExtendInt32ToInt64* ins) { defineInt64(new(alloc()) LExtendInt32ToInt64(useAtStart(ins->input())), ins); } + +void +LIRGeneratorX64::visitSignExtendInt64(MSignExtendInt64* ins) +{ + defineInt64(new(alloc()) LSignExtendInt64(useInt64RegisterAtStart(ins->input())), ins); +} + diff --git a/js/src/jit/x64/Lowering-x64.h b/js/src/jit/x64/Lowering-x64.h index 26d4d00480..09bc6f9762 100644 --- a/js/src/jit/x64/Lowering-x64.h +++ b/js/src/jit/x64/Lowering-x64.h @@ -69,6 +69,7 @@ class LIRGeneratorX64 : public LIRGeneratorX86Shared void visitWasmTruncateToInt64(MWasmTruncateToInt64* ins); void visitInt64ToFloatingPoint(MInt64ToFloatingPoint* ins); void visitExtendInt32ToInt64(MExtendInt32ToInt64* ins); + void visitSignExtendInt64(MSignExtendInt64* ins); }; typedef LIRGeneratorX64 LIRGeneratorSpecific; diff --git a/js/src/jit/x86/CodeGenerator-x86.cpp b/js/src/jit/x86/CodeGenerator-x86.cpp index 7e90076a26..3a5cc41dc8 100644 --- a/js/src/jit/x86/CodeGenerator-x86.cpp +++ b/js/src/jit/x86/CodeGenerator-x86.cpp @@ -1183,6 +1183,28 @@ CodeGeneratorX86::visitExtendInt32ToInt64(LExtendInt32ToInt64* lir) } void +CodeGeneratorX86::visitSignExtendInt64(LSignExtendInt64* lir) +{ + Register64 input = ToRegister64(lir->getInt64Operand(0)); + Register64 output = ToOutRegister64(lir); + MOZ_ASSERT(input.low == eax); + MOZ_ASSERT(output.low == eax); + MOZ_ASSERT(input.high == edx); + MOZ_ASSERT(output.high == edx); + switch (lir->mode()) { + case MSignExtendInt64::Byte: + masm.move8SignExtend(eax, eax); + break; + case MSignExtendInt64::Half: + masm.move16SignExtend(eax, eax); + break; + case MSignExtendInt64::Word: + break; + } + masm.cdq(); +} + +void CodeGeneratorX86::visitWrapInt64ToInt32(LWrapInt64ToInt32* lir) { const LInt64Allocation& input = lir->getInt64Operand(0); diff --git a/js/src/jit/x86/CodeGenerator-x86.h b/js/src/jit/x86/CodeGenerator-x86.h index e227269043..7bc48d9f3f 100644 --- a/js/src/jit/x86/CodeGenerator-x86.h +++ b/js/src/jit/x86/CodeGenerator-x86.h @@ -77,6 +77,7 @@ class CodeGeneratorX86 : public CodeGeneratorX86Shared void visitWasmReinterpretFromI64(LWasmReinterpretFromI64* lir); void visitWasmReinterpretToI64(LWasmReinterpretToI64* lir); void visitExtendInt32ToInt64(LExtendInt32ToInt64* lir); + void visitSignExtendInt64(LSignExtendInt64* ins); void visitWrapInt64ToInt32(LWrapInt64ToInt32* lir); void visitClzI64(LClzI64* lir); void visitCtzI64(LCtzI64* lir); diff --git a/js/src/jit/x86/Lowering-x86.cpp b/js/src/jit/x86/Lowering-x86.cpp index 27859c0772..fa5e5f2bbe 100644 --- a/js/src/jit/x86/Lowering-x86.cpp +++ b/js/src/jit/x86/Lowering-x86.cpp @@ -657,3 +657,14 @@ LIRGeneratorX86::visitExtendInt32ToInt64(MExtendInt32ToInt64* ins) LAllocation(AnyRegister(eax)))); } } + +void +LIRGeneratorX86::visitSignExtendInt64(MSignExtendInt64* ins) +{ + // Here we'll end up using cdq which requires input and output in (edx,eax). + LSignExtendInt64* lir = + new(alloc()) LSignExtendInt64(useInt64RegisterAtStart(ins->input())); + defineInt64Fixed(lir, ins, LInt64Allocation(LAllocation(AnyRegister(edx)), + LAllocation(AnyRegister(eax)))); +} + diff --git a/js/src/jit/x86/Lowering-x86.h b/js/src/jit/x86/Lowering-x86.h index 9f7f8b5019..32d75465a6 100644 --- a/js/src/jit/x86/Lowering-x86.h +++ b/js/src/jit/x86/Lowering-x86.h @@ -76,6 +76,7 @@ class LIRGeneratorX86 : public LIRGeneratorX86Shared void visitWasmTruncateToInt64(MWasmTruncateToInt64* ins); void visitInt64ToFloatingPoint(MInt64ToFloatingPoint* ins); void visitExtendInt32ToInt64(MExtendInt32ToInt64* ins); + void visitSignExtendInt64(MSignExtendInt64* ins); void lowerPhi(MPhi* phi); static bool allowTypedElementHoleCheck() { diff --git a/js/src/wasm/WasmBaselineCompile.cpp b/js/src/wasm/WasmBaselineCompile.cpp index 7a905ecbea..c50bef304d 100644 --- a/js/src/wasm/WasmBaselineCompile.cpp +++ b/js/src/wasm/WasmBaselineCompile.cpp @@ -2719,6 +2719,38 @@ class BaseCompiler return x0; } + RegI64 popI64ForSignExtendI64() { +#if defined(JS_CODEGEN_X86) + need2xI32(specific_edx, specific_eax); + // Low on top, high underneath + return popI64ToSpecific(RegI64(Register64(specific_edx.reg, specific_eax.reg))); +#else + return popI64(); +#endif + } + + void signExtendI64_8(RegI64 r) { +#if defined(JS_CODEGEN_X64) + masm.movsbq(Operand(r.reg.reg), r.reg.reg); +#elif defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_ARM) + masm.move8SignExtend(r.reg.low, r.reg.low); + signExtendI32ToI64(RegI32(r.reg.low), r); +#else + MOZ_CRASH("Basecompiler platform hook: signExtendI64_8"); +#endif + } + + void signExtendI64_16(RegI64 r) { +#if defined(JS_CODEGEN_X64) + masm.movswq(Operand(r.reg.reg), r.reg.reg); +#elif defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_ARM) + masm.move16SignExtend(r.reg.low, r.reg.low); + signExtendI32ToI64(RegI32(r.reg.low), r); +#else + MOZ_CRASH("Basecompiler platform hook: signExtendI64_16"); +#endif + } + void signExtendI32ToI64(RegI32 src, RegI64 dest) { #if defined(JS_CODEGEN_X64) masm.movslq(src.reg, dest.reg.reg); @@ -3707,6 +3739,11 @@ class BaseCompiler template<bool isUnsigned> MOZ_MUST_USE bool emitTruncateF64ToI64(); #endif void emitWrapI64ToI32(); + void emitExtendI32_8(); + void emitExtendI32_16(); + void emitExtendI64_8(); + void emitExtendI64_16(); + void emitExtendI64_32(); void emitExtendI32ToI64(); void emitExtendU32ToI64(); void emitReinterpretF32AsI32(); @@ -4598,6 +4635,48 @@ BaseCompiler::emitWrapI64ToI32() } void +BaseCompiler::emitExtendI32_8() +{ + RegI32 r = popI32(); + masm.move8SignExtend(r.reg, r.reg); + pushI32(r); +} + +void +BaseCompiler::emitExtendI32_16() +{ + RegI32 r = popI32(); + masm.move16SignExtend(r.reg, r.reg); + pushI32(r); +} + +void +BaseCompiler::emitExtendI64_8() +{ + RegI64 r = popI64ForSignExtendI64(); + signExtendI64_8(r); + pushI64(r); +} + +void +BaseCompiler::emitExtendI64_16() +{ + RegI64 r = popI64ForSignExtendI64(); + signExtendI64_16(r); + pushI64(r); +} + +void +BaseCompiler::emitExtendI64_32() +{ + RegI64 x0 = popI64ForSignExtendI64(); + RegI32 r0 = RegI32(lowPart(x0)); + signExtendI32ToI64(r0, x0); + pushI64(x0); + // Note: no need to free r0, since it is part of x0 +} + +void BaseCompiler::emitExtendI32ToI64() { RegI64 x0 = popI32ForSignExtendI64(); @@ -7166,6 +7245,18 @@ BaseCompiler::emitBody() case uint16_t(Op::I32AtomicsExchange): MOZ_CRASH("Unimplemented Atomics"); + // Sign extensions + case uint16_t(Op::I32Extend8S): + CHECK_NEXT(emitConversion(emitExtendI32_8, ValType::I32, ValType::I32)); + case uint16_t(Op::I32Extend16S): + CHECK_NEXT(emitConversion(emitExtendI32_16, ValType::I32, ValType::I32)); + case uint16_t(Op::I64Extend8S): + CHECK_NEXT(emitConversion(emitExtendI64_8, ValType::I64, ValType::I64)); + case uint16_t(Op::I64Extend16S): + CHECK_NEXT(emitConversion(emitExtendI64_16, ValType::I64, ValType::I64)); + case uint16_t(Op::I64Extend32S): + CHECK_NEXT(emitConversion(emitExtendI64_32, ValType::I64, ValType::I64)); + // Memory Related case uint16_t(Op::GrowMemory): CHECK_NEXT(emitGrowMemory()); diff --git a/js/src/wasm/WasmBinaryConstants.h b/js/src/wasm/WasmBinaryConstants.h index 4a5ec36b3d..59f98fca4a 100644 --- a/js/src/wasm/WasmBinaryConstants.h +++ b/js/src/wasm/WasmBinaryConstants.h @@ -310,6 +310,13 @@ enum class Op F32ReinterpretI32 = 0xbe, F64ReinterpretI64 = 0xbf, + // Sign extension + I32Extend8S = 0xc0, + I32Extend16S = 0xc1, + I64Extend8S = 0xc2, + I64Extend16S = 0xc3, + I64Extend32S = 0xc4, + // ------------------------------------------------------------------------ // The rest of these operators are currently only emitted internally when // compiling asm.js and are rejected by wasm validation. diff --git a/js/src/wasm/WasmBinaryIterator.cpp b/js/src/wasm/WasmBinaryIterator.cpp index 14371e8f22..c09c60e51a 100644 --- a/js/src/wasm/WasmBinaryIterator.cpp +++ b/js/src/wasm/WasmBinaryIterator.cpp @@ -263,22 +263,11 @@ wasm::Classify(Op op) case Op::F64ConvertUI64: case Op::F64ReinterpretI64: case Op::F64PromoteF32: - case Op::I32x4fromFloat32x4: - case Op::I32x4fromFloat32x4U: - case Op::F32x4fromInt32x4: - case Op::F32x4fromUint32x4: - case Op::I32x4fromFloat32x4Bits: - case Op::I32x4fromInt8x16Bits: - case Op::I32x4fromInt16x8Bits: - case Op::I16x8fromInt8x16Bits: - case Op::I16x8fromInt32x4Bits: - case Op::I16x8fromFloat32x4Bits: - case Op::I8x16fromInt16x8Bits: - case Op::I8x16fromInt32x4Bits: - case Op::I8x16fromFloat32x4Bits: - case Op::F32x4fromInt8x16Bits: - case Op::F32x4fromInt16x8Bits: - case Op::F32x4fromInt32x4Bits: + case Op::I32Extend8S: + case Op::I32Extend16S: + case Op::I64Extend8S: + case Op::I64Extend16S: + case Op::I64Extend32S: return OpKind::Conversion; case Op::I32Load8S: case Op::I32Load8U: diff --git a/js/src/wasm/WasmBinaryToAST.cpp b/js/src/wasm/WasmBinaryToAST.cpp index 1d17ff3062..8d6db7b357 100644 --- a/js/src/wasm/WasmBinaryToAST.cpp +++ b/js/src/wasm/WasmBinaryToAST.cpp @@ -1300,6 +1300,17 @@ AstDecodeExpr(AstDecodeContext& c) if (!AstDecodeConversion(c, ValType::F32, ValType::F64, Op(op))) return false; break; + case uint16_t(Op::I32Extend8S): + case uint16_t(Op::I32Extend16S): + if (!AstDecodeConversion(c, ValType::I32, ValType::I32, Op(op))) + return false; + break; + case uint16_t(Op::I64Extend8S): + case uint16_t(Op::I64Extend16S): + case uint16_t(Op::I64Extend32S): + if (!AstDecodeConversion(c, ValType::I64, ValType::I64, Op(op))) + return false; + break; case uint16_t(Op::I32Load8S): case uint16_t(Op::I32Load8U): if (!AstDecodeLoad(c, ValType::I32, 1, Op(op))) diff --git a/js/src/wasm/WasmBinaryToText.cpp b/js/src/wasm/WasmBinaryToText.cpp index 61df09d88a..d2b737c982 100644 --- a/js/src/wasm/WasmBinaryToText.cpp +++ b/js/src/wasm/WasmBinaryToText.cpp @@ -713,6 +713,11 @@ RenderConversionOperator(WasmRenderContext& c, AstConversionOperator& conv) case Op::F64ConvertUI64: opStr = "f64.convert_u/i64"; break; case Op::F64ReinterpretI64: opStr = "f64.reinterpret/i64"; break; case Op::F64PromoteF32: opStr = "f64.promote/f32"; break; + case Op::I32Extend8S: opStr = "i32.extend8_s"; break; + case Op::I32Extend16S: opStr = "i32.extend16_s"; break; + case Op::I64Extend8S: opStr = "i64.extend8_s"; break; + case Op::I64Extend16S: opStr = "i64.extend16_s"; break; + case Op::I64Extend32S: opStr = "i64.extend32_s"; break; case Op::I32Eqz: opStr = "i32.eqz"; break; case Op::I64Eqz: opStr = "i64.eqz"; break; default: return Fail(c, "unexpected conversion operator"); diff --git a/js/src/wasm/WasmCompile.cpp b/js/src/wasm/WasmCompile.cpp index c15bd89f83..ec518637d4 100644 --- a/js/src/wasm/WasmCompile.cpp +++ b/js/src/wasm/WasmCompile.cpp @@ -347,6 +347,13 @@ DecodeFunctionBodyExprs(FunctionDecoder& f) CHECK(f.iter().readConversion(ValType::I64, ValType::F64, nullptr)); case uint16_t(Op::F64PromoteF32): CHECK(f.iter().readConversion(ValType::F32, ValType::F64, nullptr)); + case uint16_t(Op::I32Extend8S): + case uint16_t(Op::I32Extend16S): + CHECK(f.iter().readConversion(ValType::I32, ValType::I32, nullptr)); + case uint16_t(Op::I64Extend8S): + case uint16_t(Op::I64Extend16S): + case uint16_t(Op::I64Extend32S): + CHECK(f.iter().readConversion(ValType::I64, ValType::I64, nullptr)); case uint16_t(Op::I32Load8S): case uint16_t(Op::I32Load8U): CHECK(f.checkHasMemory() && f.iter().readLoad(ValType::I32, 1, nullptr)); diff --git a/js/src/wasm/WasmIonCompile.cpp b/js/src/wasm/WasmIonCompile.cpp index 2b16d3f053..a41a7f961e 100644 --- a/js/src/wasm/WasmIonCompile.cpp +++ b/js/src/wasm/WasmIonCompile.cpp @@ -666,6 +666,41 @@ class FunctionCompiler return ins; } + MDefinition* signExtend(MDefinition* op, uint32_t srcSize, uint32_t targetSize) + { + if (inDeadCode()) + return nullptr; + MInstruction* ins; + switch (targetSize) { + case 4: { + MSignExtendInt32::Mode mode; + switch (srcSize) { + case 1: mode = MSignExtendInt32::Byte; break; + case 2: mode = MSignExtendInt32::Half; break; + default: MOZ_CRASH("Bad sign extension"); + } + ins = MSignExtendInt32::New(alloc(), op, mode); + break; + } + case 8: { + MSignExtendInt64::Mode mode; + switch (srcSize) { + case 1: mode = MSignExtendInt64::Byte; break; + case 2: mode = MSignExtendInt64::Half; break; + case 4: mode = MSignExtendInt64::Word; break; + default: MOZ_CRASH("Bad sign extension"); + } + ins = MSignExtendInt64::New(alloc(), op, mode); + break; + } + default: { + MOZ_CRASH("Bad sign extension"); + } + } + curBlock_->add(ins); + return ins; + } + MDefinition* convertI64ToFloatingPoint(MDefinition* op, MIRType type, bool isUnsigned) { if (inDeadCode()) @@ -2182,6 +2217,18 @@ EmitTruncate(FunctionCompiler& f, ValType operandType, ValType resultType, } static bool +EmitSignExtend(FunctionCompiler& f, uint32_t srcSize, uint32_t targetSize) +{ + MDefinition* input; + ValType type = targetSize == 4 ? ValType::I32 : ValType::I64; + if (!f.iter().readConversion(type, type, &input)) + return false; + + f.iter().setResult(f.signExtend(input, srcSize, targetSize)); + return true; +} + +static bool EmitExtendI32(FunctionCompiler& f, bool isUnsigned) { MDefinition* input; @@ -3480,6 +3527,18 @@ EmitExpr(FunctionCompiler& f) case Op::F64ReinterpretI64: return EmitReinterpret(f, ValType::F64, ValType::I64, MIRType::Double); + // Sign extensions + case Op::I32Extend8S: + return EmitSignExtend(f, 1, 4); + case Op::I32Extend16S: + return EmitSignExtend(f, 2, 4); + case Op::I64Extend8S: + return EmitSignExtend(f, 1, 8); + case Op::I64Extend16S: + return EmitSignExtend(f, 2, 8); + case Op::I64Extend32S: + return EmitSignExtend(f, 4, 8); + // Comparisons case Op::I32Eq: return EmitComparison(f, ValType::I32, JSOP_EQ, MCompare::Compare_Int32); diff --git a/js/src/wasm/WasmTextToBinary.cpp b/js/src/wasm/WasmTextToBinary.cpp index db1811ad7e..c3a707b550 100644 --- a/js/src/wasm/WasmTextToBinary.cpp +++ b/js/src/wasm/WasmTextToBinary.cpp @@ -925,6 +925,16 @@ WasmTokenStream::next() case 'e': if (consume(u"eq")) return WasmToken(WasmToken::ComparisonOpcode, Op::F32Eq, begin, cur_); + if (consume(u"extend8_s")) + return WasmToken(WasmToken::ConversionOpcode, Op::I32Extend8S, begin, cur_); + if (consume(u"extend16_s")) + return WasmToken(WasmToken::ConversionOpcode, Op::I32Extend16S, begin, cur_); + if (consume(u"extend8_s")) + return WasmToken(WasmToken::ConversionOpcode, Op::I64Extend8S, begin, cur_); + if (consume(u"extend16_s")) + return WasmToken(WasmToken::ConversionOpcode, Op::I64Extend16S, begin, cur_); + if (consume(u"extend32_s")) + return WasmToken(WasmToken::ConversionOpcode, Op::I64Extend32S, begin, cur_); break; case 'f': if (consume(u"floor")) |