summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrian Smith <brian@dbsoft.org>2023-09-22 13:23:36 -0500
committerMoonchild <moonchild@palemoon.org>2023-09-25 10:46:25 +0200
commitf96b1559881debb518ad5e27f1754363fd6280ed (patch)
tree48eb99e9451d69a45de7540c2f7b924bb8eec941
parentd5cc24e91620a621217210b292a2ec53d6c01f42 (diff)
downloaduxp-f96b1559881debb518ad5e27f1754363fd6280ed.tar.gz
Issue #2313 - Implement WebAssembly sign extension opcodes. (uplift)
-rw-r--r--js/src/jit-test/lib/wasm-binary.js2
-rw-r--r--js/src/jit/CodeGenerator.cpp6
-rw-r--r--js/src/jit/CodeGenerator.h2
-rw-r--r--js/src/jit/Lowering.cpp8
-rw-r--r--js/src/jit/Lowering.h2
-rw-r--r--js/src/jit/MIR.cpp39
-rw-r--r--js/src/jit/MIR.h60
-rw-r--r--js/src/jit/MOpcodes.h3
-rw-r--r--js/src/jit/Recover.cpp14
-rw-r--r--js/src/jit/Recover.h6
-rw-r--r--js/src/jit/arm/CodeGenerator-arm.cpp18
-rw-r--r--js/src/jit/arm/CodeGenerator-arm.h1
-rw-r--r--js/src/jit/arm/Lowering-arm.cpp6
-rw-r--r--js/src/jit/arm/Lowering-arm.h1
-rw-r--r--js/src/jit/arm64/Lowering-arm64.cpp6
-rw-r--r--js/src/jit/arm64/Lowering-arm64.h1
-rw-r--r--js/src/jit/none/Lowering-none.h1
-rw-r--r--js/src/jit/shared/LIR-shared.h25
-rw-r--r--js/src/jit/shared/LOpcodes-shared.h3
-rw-r--r--js/src/jit/x64/Assembler-x64.h6
-rw-r--r--js/src/jit/x64/BaseAssembler-x64.h10
-rw-r--r--js/src/jit/x64/CodeGenerator-x64.cpp18
-rw-r--r--js/src/jit/x64/CodeGenerator-x64.h1
-rw-r--r--js/src/jit/x64/Lowering-x64.cpp7
-rw-r--r--js/src/jit/x64/Lowering-x64.h1
-rw-r--r--js/src/jit/x86/CodeGenerator-x86.cpp22
-rw-r--r--js/src/jit/x86/CodeGenerator-x86.h1
-rw-r--r--js/src/jit/x86/Lowering-x86.cpp11
-rw-r--r--js/src/jit/x86/Lowering-x86.h1
-rw-r--r--js/src/wasm/WasmBaselineCompile.cpp91
-rw-r--r--js/src/wasm/WasmBinaryConstants.h7
-rw-r--r--js/src/wasm/WasmBinaryIterator.cpp21
-rw-r--r--js/src/wasm/WasmBinaryToAST.cpp11
-rw-r--r--js/src/wasm/WasmBinaryToText.cpp5
-rw-r--r--js/src/wasm/WasmCompile.cpp7
-rw-r--r--js/src/wasm/WasmIonCompile.cpp59
-rw-r--r--js/src/wasm/WasmTextToBinary.cpp10
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"))