From 0c97a6410ff018c22e65a0cbe4e5f2ca4581b22e Mon Sep 17 00:00:00 2001 From: Dmitry Bezhetskov Date: Mon, 14 Sep 2020 05:19:44 +0000 Subject: [PATCH] Bug 1639153 - Part 6.6: Add tls dependency for truncate i32. r=lth We generate builtin call for MTruncateToInt32 operation for floating points types, so we need to add a tls dependency. I inserted NYI for arm64 because Ion doesn't support arm64. Differential Revision: https://phabricator.services.mozilla.com/D89550 --- js/src/jit/Lowering.cpp | 10 ++ js/src/jit/MIR.h | 35 ++++++ js/src/jit/MacroAssembler.cpp | 5 +- js/src/jit/MacroAssembler.h | 3 +- js/src/jit/arm/CodeGenerator-arm.cpp | 12 ++ js/src/jit/arm/Lowering-arm.cpp | 19 ++++ js/src/jit/arm/Lowering-arm.h | 1 + js/src/jit/arm64/CodeGenerator-arm64.cpp | 10 ++ js/src/jit/arm64/Lowering-arm64.cpp | 5 + js/src/jit/arm64/Lowering-arm64.h | 1 + .../mips-shared/CodeGenerator-mips-shared.cpp | 10 ++ .../jit/mips-shared/Lowering-mips-shared.cpp | 5 + js/src/jit/mips-shared/Lowering-mips-shared.h | 1 + js/src/jit/none/Lowering-none.h | 3 + js/src/jit/shared/CodeGenerator-shared.cpp | 50 +++++++- js/src/jit/shared/CodeGenerator-shared.h | 7 +- js/src/jit/shared/LIR-shared.h | 42 +++++++ js/src/jit/x64/CodeGenerator-x64.cpp | 16 +++ js/src/jit/x86-shared/Lowering-x86-shared.cpp | 21 ++++ js/src/jit/x86-shared/Lowering-x86-shared.h | 1 + js/src/jit/x86/CodeGenerator-x86.cpp | 107 +++++++++++++++--- js/src/wasm/WasmIonCompile.cpp | 34 ++++-- 22 files changed, 361 insertions(+), 37 deletions(-) diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp index aaabe91833db..019e3fb4809d 100644 --- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -2357,6 +2357,16 @@ void LIRGenerator::visitWasmTruncateToInt32(MWasmTruncateToInt32* ins) { } } +void LIRGenerator::visitWasmBuiltinTruncateToInt32( + MWasmBuiltinTruncateToInt32* truncate) { + mozilla::DebugOnly opd = truncate->input(); + MOZ_ASSERT(opd->type() == MIRType::Double || opd->type() == MIRType::Float32); + + // May call into JS::ToInt32() on the slow OOL path. + gen->setNeedsStaticStackAlignment(); + lowerWasmBuiltinTruncateToInt32(truncate); +} + void LIRGenerator::visitWasmBoxValue(MWasmBoxValue* ins) { LWasmBoxValue* lir = new (alloc()) LWasmBoxValue(useBox(ins->input())); define(lir, ins); diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index a3ced46a44b2..e302324b8664 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -4368,6 +4368,41 @@ class MTruncateToInt32 : public MUnaryInstruction, public ToInt32Policy::Data { ALLOW_CLONE(MTruncateToInt32) }; +// It is like MTruncateToInt32 but with tls dependency. +class MWasmBuiltinTruncateToInt32 : public MAryInstruction<2>, + public ToInt32Policy::Data { + wasm::BytecodeOffset bytecodeOffset_; + + MWasmBuiltinTruncateToInt32( + MDefinition* def, MDefinition* tls, + wasm::BytecodeOffset bytecodeOffset = wasm::BytecodeOffset()) + : MAryInstruction(classOpcode), bytecodeOffset_(bytecodeOffset) { + initOperand(0, def); + initOperand(1, tls); + setResultType(MIRType::Int32); + setMovable(); + + // Guard unless the conversion is known to be non-effectful & non-throwing. + if (MTruncateToInt32::mightHaveSideEffects(def)) { + setGuard(); + } + } + + public: + INSTRUCTION_HEADER(WasmBuiltinTruncateToInt32) + NAMED_OPERANDS((0, input), (1, tls)) + TRIVIAL_NEW_WRAPPERS + + bool congruentTo(const MDefinition* ins) const override { + return congruentIfOperandsEqual(ins); + } + AliasSet getAliasSet() const override { return AliasSet::None(); } + + wasm::BytecodeOffset bytecodeOffset() const { return bytecodeOffset_; } + + ALLOW_CLONE(MWasmBuiltinTruncateToInt32) +}; + // Converts a primitive (either typed or untyped) to a BigInt. If the input is // not primitive at runtime, a bailout occurs. class MToBigInt : public MUnaryInstruction, public ToBigIntPolicy::Data { diff --git a/js/src/jit/MacroAssembler.cpp b/js/src/jit/MacroAssembler.cpp index debab263af0d..cd284ed839d5 100644 --- a/js/src/jit/MacroAssembler.cpp +++ b/js/src/jit/MacroAssembler.cpp @@ -2431,7 +2431,8 @@ void MacroAssembler::convertValueToFloatingPoint(ValueOperand value, void MacroAssembler::outOfLineTruncateSlow(FloatRegister src, Register dest, bool widenFloatToDouble, bool compilingWasm, - wasm::BytecodeOffset callOffset) { + wasm::BytecodeOffset callOffset, + mozilla::Maybe tlsOffset) { #if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || \ defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) ScratchDoubleScope fpscratch(*this); @@ -2458,7 +2459,7 @@ void MacroAssembler::outOfLineTruncateSlow(FloatRegister src, Register dest, if (compilingWasm) { setupWasmABICall(); passABIArg(src, MoveOp::DOUBLE); - callWithABI(callOffset, wasm::SymbolicAddress::ToInt32, mozilla::Nothing()); + callWithABI(callOffset, wasm::SymbolicAddress::ToInt32, tlsOffset); } else { setupUnalignedABICall(dest); passABIArg(src, MoveOp::DOUBLE); diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h index 2f8da3e6d509..072d01f2bb3b 100644 --- a/js/src/jit/MacroAssembler.h +++ b/js/src/jit/MacroAssembler.h @@ -3959,7 +3959,8 @@ class MacroAssembler : public MacroAssemblerSpecific { void outOfLineTruncateSlow(FloatRegister src, Register dest, bool widenFloatToDouble, bool compilingWasm, - wasm::BytecodeOffset callOffset); + wasm::BytecodeOffset callOffset, + mozilla::Maybe tlsOffset); void convertInt32ValueToDouble(const Address& address, Register scratch, Label* done); diff --git a/js/src/jit/arm/CodeGenerator-arm.cpp b/js/src/jit/arm/CodeGenerator-arm.cpp index c2de8c773d0e..a66016664833 100644 --- a/js/src/jit/arm/CodeGenerator-arm.cpp +++ b/js/src/jit/arm/CodeGenerator-arm.cpp @@ -1195,11 +1195,23 @@ void CodeGenerator::visitTruncateDToInt32(LTruncateDToInt32* ins) { ins->mir()); } +void CodeGenerator::visitWasmBuiltinTruncateDToInt32( + LWasmBuiltinTruncateDToInt32* ins) { + emitTruncateDoubleBuiltin(ToFloatRegister(ins->getOperand(0)), + ToRegister(ins->getDef(0)), ins->mir()); +} + void CodeGenerator::visitTruncateFToInt32(LTruncateFToInt32* ins) { emitTruncateFloat32(ToFloatRegister(ins->input()), ToRegister(ins->output()), ins->mir()); } +void CodeGenerator::visitWasmBuiltinTruncateFToInt32( + LWasmBuiltinTruncateFToInt32* ins) { + emitTruncateFloat32Builtin(ToFloatRegister(ins->getOperand(0)), + ToRegister(ins->getDef(0)), ins->mir()); +} + static const uint32_t FrameSizes[] = {128, 256, 512, 1024}; FrameSizeClass FrameSizeClass::FromDepth(uint32_t frameDepth) { diff --git a/js/src/jit/arm/Lowering-arm.cpp b/js/src/jit/arm/Lowering-arm.cpp index 6bafec5796cc..d787c718615e 100644 --- a/js/src/jit/arm/Lowering-arm.cpp +++ b/js/src/jit/arm/Lowering-arm.cpp @@ -262,6 +262,25 @@ void LIRGeneratorARM::lowerForBitAndAndBranch(LBitAndAndBranch* baab, add(baab, mir); } +void LIRGeneratorARM::lowerWasmBuiltinTruncateToInt32( + MWasmBuiltinTruncateToInt32* ins) { + MDefinition* opd = ins->input(); + MOZ_ASSERT(opd->type() == MIRType::Double || opd->type() == MIRType::Float32); + + if (opd->type() == MIRType::Double) { + define(new (alloc()) LWasmBuiltinTruncateDToInt32( + useRegister(opd), useFixedAtStart(ins->tls(), WasmTlsReg), + LDefinition::BogusTemp()), + ins); + return; + } + + define(new (alloc()) LWasmBuiltinTruncateFToInt32( + useRegister(opd), useFixedAtStart(ins->tls(), WasmTlsReg), + LDefinition::BogusTemp()), + ins); +} + void LIRGeneratorARM::lowerUntypedPhiInput(MPhi* phi, uint32_t inputPosition, LBlock* block, size_t lirIndex) { MDefinition* operand = phi->getOperand(inputPosition); diff --git a/js/src/jit/arm/Lowering-arm.h b/js/src/jit/arm/Lowering-arm.h index 0b5f7f9ac2b4..1b7aa65f1f13 100644 --- a/js/src/jit/arm/Lowering-arm.h +++ b/js/src/jit/arm/Lowering-arm.h @@ -69,6 +69,7 @@ class LIRGeneratorARM : public LIRGeneratorShared { void lowerWasmBuiltinTruncateToInt64(MWasmBuiltinTruncateToInt64* ins); void lowerForBitAndAndBranch(LBitAndAndBranch* baab, MInstruction* mir, MDefinition* lhs, MDefinition* rhs); + void lowerWasmBuiltinTruncateToInt32(MWasmBuiltinTruncateToInt32* ins); void lowerTruncateDToInt32(MTruncateToInt32* ins); void lowerTruncateFToInt32(MTruncateToInt32* ins); void lowerDivI(MDiv* div); diff --git a/js/src/jit/arm64/CodeGenerator-arm64.cpp b/js/src/jit/arm64/CodeGenerator-arm64.cpp index 414f16c86db9..271ad6d52202 100644 --- a/js/src/jit/arm64/CodeGenerator-arm64.cpp +++ b/js/src/jit/arm64/CodeGenerator-arm64.cpp @@ -1162,11 +1162,21 @@ void CodeGenerator::visitTruncateDToInt32(LTruncateDToInt32* ins) { ins->mir()); } +void CodeGenerator::visitWasmBuiltinTruncateDToInt32( + LWasmBuiltinTruncateDToInt32* lir) { + MOZ_CRASH("NYI"); +} + void CodeGenerator::visitTruncateFToInt32(LTruncateFToInt32* ins) { emitTruncateFloat32(ToFloatRegister(ins->input()), ToRegister(ins->output()), ins->mir()); } +void CodeGenerator::visitWasmBuiltinTruncateFToInt32( + LWasmBuiltinTruncateFToInt32* lir) { + MOZ_CRASH("NYI"); +} + FrameSizeClass FrameSizeClass::FromDepth(uint32_t frameDepth) { return FrameSizeClass::None(); } diff --git a/js/src/jit/arm64/Lowering-arm64.cpp b/js/src/jit/arm64/Lowering-arm64.cpp index 7d3c3db6bc88..47c21d5dc2f1 100644 --- a/js/src/jit/arm64/Lowering-arm64.cpp +++ b/js/src/jit/arm64/Lowering-arm64.cpp @@ -186,6 +186,11 @@ void LIRGeneratorARM64::lowerForBitAndAndBranch(LBitAndAndBranch* baab, add(baab, mir); } +void LIRGeneratorARM64::lowerWasmBuiltinTruncateToInt32( + MWasmBuiltinTruncateToInt32* ins) { + MOZ_CRASH("NYI"); +} + void LIRGeneratorARM64::lowerUntypedPhiInput(MPhi* phi, uint32_t inputPosition, LBlock* block, size_t lirIndex) { lowerTypedPhiInput(phi, inputPosition, block, lirIndex); diff --git a/js/src/jit/arm64/Lowering-arm64.h b/js/src/jit/arm64/Lowering-arm64.h index 1f0b0d369575..2ce217180d8f 100644 --- a/js/src/jit/arm64/Lowering-arm64.h +++ b/js/src/jit/arm64/Lowering-arm64.h @@ -72,6 +72,7 @@ class LIRGeneratorARM64 : public LIRGeneratorShared { void lowerWasmBuiltinTruncateToInt64(MWasmBuiltinTruncateToInt64* ins); void lowerForBitAndAndBranch(LBitAndAndBranch* baab, MInstruction* mir, MDefinition* lhs, MDefinition* rhs); + void lowerWasmBuiltinTruncateToInt32(MWasmBuiltinTruncateToInt32* ins); void lowerTruncateDToInt32(MTruncateToInt32* ins); void lowerTruncateFToInt32(MTruncateToInt32* ins); void lowerDivI(MDiv* div); diff --git a/js/src/jit/mips-shared/CodeGenerator-mips-shared.cpp b/js/src/jit/mips-shared/CodeGenerator-mips-shared.cpp index 5af0a7cd730d..a56841864eeb 100644 --- a/js/src/jit/mips-shared/CodeGenerator-mips-shared.cpp +++ b/js/src/jit/mips-shared/CodeGenerator-mips-shared.cpp @@ -1130,6 +1130,16 @@ void CodeGenerator::visitTruncateFToInt32(LTruncateFToInt32* ins) { ins->mir()); } +void CodeGenerator::visitWasmBuiltinTruncateDToInt32( + LWasmBuiltinTruncateDToInt32* lir) { + MOZ_CRASH("NYI"); +} + +void CodeGenerator::visitWasmBuiltinTruncateFToInt32( + LWasmBuiltinTruncateFToInt32* lir) { + MOZ_CRASH("NYI"); +} + void CodeGenerator::visitWasmTruncateToInt32(LWasmTruncateToInt32* lir) { auto input = ToFloatRegister(lir->input()); auto output = ToRegister(lir->output()); diff --git a/js/src/jit/mips-shared/Lowering-mips-shared.cpp b/js/src/jit/mips-shared/Lowering-mips-shared.cpp index 0b639a7ecf17..a6f054d58ec3 100644 --- a/js/src/jit/mips-shared/Lowering-mips-shared.cpp +++ b/js/src/jit/mips-shared/Lowering-mips-shared.cpp @@ -180,6 +180,11 @@ void LIRGeneratorMIPSShared::lowerForBitAndAndBranch(LBitAndAndBranch* baab, add(baab, mir); } +void LIRGeneratorMIPSShared::lowerWasmBuiltinTruncateToInt32( + MWasmBuiltinTruncateToInt32* ins) { + MOZ_CRASH("NYI"); +} + void LIRGeneratorMIPSShared::lowerForShift(LInstructionHelper<1, 2, 0>* ins, MDefinition* mir, MDefinition* lhs, MDefinition* rhs) { diff --git a/js/src/jit/mips-shared/Lowering-mips-shared.h b/js/src/jit/mips-shared/Lowering-mips-shared.h index aca283d0533e..b7e556b2dde5 100644 --- a/js/src/jit/mips-shared/Lowering-mips-shared.h +++ b/js/src/jit/mips-shared/Lowering-mips-shared.h @@ -55,6 +55,7 @@ class LIRGeneratorMIPSShared : public LIRGeneratorShared { void lowerForBitAndAndBranch(LBitAndAndBranch* baab, MInstruction* mir, MDefinition* lhs, MDefinition* rhs); + void lowerWasmBuiltinTruncateToInt32(MWasmBuiltinTruncateToInt32* ins); void lowerDivI(MDiv* div); void lowerModI(MMod* mod); void lowerMulI(MMul* mul, MDefinition* lhs, MDefinition* rhs); diff --git a/js/src/jit/none/Lowering-none.h b/js/src/jit/none/Lowering-none.h index e5263e95f893..48d764ad08ec 100644 --- a/js/src/jit/none/Lowering-none.h +++ b/js/src/jit/none/Lowering-none.h @@ -70,6 +70,9 @@ class LIRGeneratorNone : public LIRGeneratorShared { void lowerConstantDouble(double, MInstruction*) { MOZ_CRASH(); } void lowerConstantFloat32(float, MInstruction*) { MOZ_CRASH(); } + void lowerWasmBuiltinTruncateToInt32(MWasmBuiltinTruncateToInt32*) { + MOZ_CRASH(); + } void lowerTruncateDToInt32(MTruncateToInt32*) { MOZ_CRASH(); } void lowerTruncateFToInt32(MTruncateToInt32*) { MOZ_CRASH(); } void lowerBuiltinInt64ToFloatingPoint(MBuiltinInt64ToFloatingPoint* ins) { diff --git a/js/src/jit/shared/CodeGenerator-shared.cpp b/js/src/jit/shared/CodeGenerator-shared.cpp index 0e421831e27a..3a2d27279f67 100644 --- a/js/src/jit/shared/CodeGenerator-shared.cpp +++ b/js/src/jit/shared/CodeGenerator-shared.cpp @@ -886,15 +886,18 @@ class OutOfLineTruncateSlow : public OutOfLineCodeBase { Register dest_; bool widenFloatToDouble_; wasm::BytecodeOffset bytecodeOffset_; + bool preserveTls_; public: OutOfLineTruncateSlow( FloatRegister src, Register dest, bool widenFloatToDouble = false, - wasm::BytecodeOffset bytecodeOffset = wasm::BytecodeOffset()) + wasm::BytecodeOffset bytecodeOffset = wasm::BytecodeOffset(), + bool preserveTls = false) : src_(src), dest_(dest), widenFloatToDouble_(widenFloatToDouble), - bytecodeOffset_(bytecodeOffset) {} + bytecodeOffset_(bytecodeOffset), + preserveTls_(preserveTls) {} void accept(CodeGeneratorShared* codegen) override { codegen->visitOutOfLineTruncateSlow(this); @@ -902,16 +905,17 @@ class OutOfLineTruncateSlow : public OutOfLineCodeBase { FloatRegister src() const { return src_; } Register dest() const { return dest_; } bool widenFloatToDouble() const { return widenFloatToDouble_; } + bool preserveTls() const { return preserveTls_; } wasm::BytecodeOffset bytecodeOffset() const { return bytecodeOffset_; } }; OutOfLineCode* CodeGeneratorShared::oolTruncateDouble( FloatRegister src, Register dest, MInstruction* mir, - wasm::BytecodeOffset bytecodeOffset) { + wasm::BytecodeOffset bytecodeOffset, bool preserveTls) { MOZ_ASSERT_IF(IsCompilingWasm(), bytecodeOffset.isValid()); - OutOfLineTruncateSlow* ool = new (alloc()) - OutOfLineTruncateSlow(src, dest, /* float32 */ false, bytecodeOffset); + OutOfLineTruncateSlow* ool = new (alloc()) OutOfLineTruncateSlow( + src, dest, /* float32 */ false, bytecodeOffset, preserveTls); addOutOfLineCode(ool, mir); return ool; } @@ -924,6 +928,15 @@ void CodeGeneratorShared::emitTruncateDouble(FloatRegister src, Register dest, masm.bind(ool->rejoin()); } +void CodeGeneratorShared::emitTruncateDoubleBuiltin( + FloatRegister src, Register dest, MWasmBuiltinTruncateToInt32* mir) { + OutOfLineCode* ool = oolTruncateDouble(src, dest, mir, mir->bytecodeOffset(), + /* preserveTls */ true); + + masm.branchTruncateDoubleMaybeModUint32(src, dest, ool->entry()); + masm.bind(ool->rejoin()); +} + void CodeGeneratorShared::emitTruncateFloat32(FloatRegister src, Register dest, MTruncateToInt32* mir) { OutOfLineTruncateSlow* ool = new (alloc()) OutOfLineTruncateSlow( @@ -934,16 +947,41 @@ void CodeGeneratorShared::emitTruncateFloat32(FloatRegister src, Register dest, masm.bind(ool->rejoin()); } +void CodeGeneratorShared::emitTruncateFloat32Builtin( + FloatRegister src, Register dest, MWasmBuiltinTruncateToInt32* mir) { + OutOfLineTruncateSlow* ool = new (alloc()) + OutOfLineTruncateSlow(src, dest, /* float32 */ true, + mir->bytecodeOffset(), /* preserveTls */ true); + addOutOfLineCode(ool, mir); + + masm.branchTruncateFloat32MaybeModUint32(src, dest, ool->entry()); + masm.bind(ool->rejoin()); +} + void CodeGeneratorShared::visitOutOfLineTruncateSlow( OutOfLineTruncateSlow* ool) { FloatRegister src = ool->src(); Register dest = ool->dest(); + if (ool->preserveTls()) { + masm.Push(WasmTlsReg); + } + int32_t framePushedAfterTls = masm.framePushed(); + saveVolatile(dest); + mozilla::Maybe tlsOffset = + ool->preserveTls() + ? mozilla::Some(masm.framePushed() - framePushedAfterTls) + : mozilla::Nothing(); masm.outOfLineTruncateSlow(src, dest, ool->widenFloatToDouble(), - gen->compilingWasm(), ool->bytecodeOffset()); + gen->compilingWasm(), ool->bytecodeOffset(), + tlsOffset); restoreVolatile(dest); + if (ool->preserveTls()) { + masm.Pop(WasmTlsReg); + } + masm.jump(ool->rejoin()); } diff --git a/js/src/jit/shared/CodeGenerator-shared.h b/js/src/jit/shared/CodeGenerator-shared.h index f35468e21651..c97e93e15f42 100644 --- a/js/src/jit/shared/CodeGenerator-shared.h +++ b/js/src/jit/shared/CodeGenerator-shared.h @@ -279,11 +279,16 @@ class CodeGeneratorShared : public LElementVisitor { OutOfLineCode* oolTruncateDouble( FloatRegister src, Register dest, MInstruction* mir, - wasm::BytecodeOffset callOffset = wasm::BytecodeOffset()); + wasm::BytecodeOffset callOffset = wasm::BytecodeOffset(), + bool preserveTls = false); void emitTruncateDouble(FloatRegister src, Register dest, MTruncateToInt32* mir); + void emitTruncateDoubleBuiltin(FloatRegister src, Register dest, + MWasmBuiltinTruncateToInt32* mir); void emitTruncateFloat32(FloatRegister src, Register dest, MTruncateToInt32* mir); + void emitTruncateFloat32Builtin(FloatRegister src, Register dest, + MWasmBuiltinTruncateToInt32* mir); void emitPreBarrier(Register elements, const LAllocation* index); void emitPreBarrier(Address address); diff --git a/js/src/jit/shared/LIR-shared.h b/js/src/jit/shared/LIR-shared.h index c03addf39718..a3386fd2e013 100644 --- a/js/src/jit/shared/LIR-shared.h +++ b/js/src/jit/shared/LIR-shared.h @@ -3124,6 +3124,27 @@ class LTruncateDToInt32 : public LInstructionHelper<1, 1, 1> { MTruncateToInt32* mir() const { return mir_->toTruncateToInt32(); } }; +// Convert a double to a truncated int32, carrying the tls value because we need +// it for the slow ool path. +class LWasmBuiltinTruncateDToInt32 : public LInstructionHelper<1, 2, 1> { + public: + LIR_HEADER(WasmBuiltinTruncateDToInt32) + + LWasmBuiltinTruncateDToInt32(const LAllocation& in, const LAllocation& tls, + const LDefinition& temp) + : LInstructionHelper(classOpcode) { + setOperand(0, in); + setOperand(1, tls); + setTemp(0, temp); + } + + const LDefinition* tempFloat() { return getTemp(0); } + + MWasmBuiltinTruncateToInt32* mir() const { + return mir_->toWasmBuiltinTruncateToInt32(); + } +}; + // Convert a float32 to a truncated int32. // Input: floating-point register // Output: 32-bit integer @@ -3142,6 +3163,27 @@ class LTruncateFToInt32 : public LInstructionHelper<1, 1, 1> { MTruncateToInt32* mir() const { return mir_->toTruncateToInt32(); } }; +// Convert a float32 to a truncated int32, carrying the tls value because we +// need it for the slow ool path. +class LWasmBuiltinTruncateFToInt32 : public LInstructionHelper<1, 2, 1> { + public: + LIR_HEADER(WasmBuiltinTruncateFToInt32) + + LWasmBuiltinTruncateFToInt32(const LAllocation& in, const LAllocation& tls, + const LDefinition& temp) + : LInstructionHelper(classOpcode) { + setOperand(0, in); + setOperand(1, tls); + setTemp(0, temp); + } + + const LDefinition* tempFloat() { return getTemp(0); } + + MWasmBuiltinTruncateToInt32* mir() const { + return mir_->toWasmBuiltinTruncateToInt32(); + } +}; + class LWasmTruncateToInt32 : public LInstructionHelper<1, 1, 0> { public: LIR_HEADER(WasmTruncateToInt32) diff --git a/js/src/jit/x64/CodeGenerator-x64.cpp b/js/src/jit/x64/CodeGenerator-x64.cpp index ca9cf20586fb..72595e1ef6b2 100644 --- a/js/src/jit/x64/CodeGenerator-x64.cpp +++ b/js/src/jit/x64/CodeGenerator-x64.cpp @@ -578,6 +578,22 @@ void CodeGenerator::visitTruncateDToInt32(LTruncateDToInt32* ins) { emitTruncateDouble(input, output, ins->mir()); } +void CodeGenerator::visitWasmBuiltinTruncateDToInt32( + LWasmBuiltinTruncateDToInt32* lir) { + FloatRegister input = ToFloatRegister(lir->getOperand(0)); + Register output = ToRegister(lir->getDef(0)); + + emitTruncateDoubleBuiltin(input, output, lir->mir()); +} + +void CodeGenerator::visitWasmBuiltinTruncateFToInt32( + LWasmBuiltinTruncateFToInt32* lir) { + FloatRegister input = ToFloatRegister(lir->getOperand(0)); + Register output = ToRegister(lir->getDef(0)); + + emitTruncateFloat32Builtin(input, output, lir->mir()); +} + void CodeGenerator::visitTruncateFToInt32(LTruncateFToInt32* ins) { FloatRegister input = ToFloatRegister(ins->input()); Register output = ToRegister(ins->output()); diff --git a/js/src/jit/x86-shared/Lowering-x86-shared.cpp b/js/src/jit/x86-shared/Lowering-x86-shared.cpp index c1aaa8b59951..0e9485058632 100644 --- a/js/src/jit/x86-shared/Lowering-x86-shared.cpp +++ b/js/src/jit/x86-shared/Lowering-x86-shared.cpp @@ -450,6 +450,27 @@ void LIRGeneratorX86Shared::lowerPowOfTwoI(MPow* mir) { define(lir, mir); } +void LIRGeneratorX86Shared::lowerWasmBuiltinTruncateToInt32( + MWasmBuiltinTruncateToInt32* ins) { + MDefinition* opd = ins->input(); + MOZ_ASSERT(opd->type() == MIRType::Double || opd->type() == MIRType::Float32); + + LDefinition maybeTemp = + Assembler::HasSSE3() ? LDefinition::BogusTemp() : tempDouble(); + if (opd->type() == MIRType::Double) { + define(new (alloc()) LWasmBuiltinTruncateDToInt32( + useRegister(opd), useFixedAtStart(ins->tls(), WasmTlsReg), + maybeTemp), + ins); + return; + } + + define( + new (alloc()) LWasmBuiltinTruncateFToInt32( + useRegister(opd), useFixedAtStart(ins->tls(), WasmTlsReg), maybeTemp), + ins); +} + void LIRGeneratorX86Shared::lowerTruncateDToInt32(MTruncateToInt32* ins) { MDefinition* opd = ins->input(); MOZ_ASSERT(opd->type() == MIRType::Double); diff --git a/js/src/jit/x86-shared/Lowering-x86-shared.h b/js/src/jit/x86-shared/Lowering-x86-shared.h index b7711fda6ece..cdbc912ef7c1 100644 --- a/js/src/jit/x86-shared/Lowering-x86-shared.h +++ b/js/src/jit/x86-shared/Lowering-x86-shared.h @@ -46,6 +46,7 @@ class LIRGeneratorX86Shared : public LIRGeneratorShared { void lowerUMod(MMod* mod); void lowerUrshD(MUrsh* mir); void lowerPowOfTwoI(MPow* mir); + void lowerWasmBuiltinTruncateToInt32(MWasmBuiltinTruncateToInt32* ins); void lowerTruncateDToInt32(MTruncateToInt32* ins); void lowerTruncateFToInt32(MTruncateToInt32* ins); void lowerCompareExchangeTypedArrayElement( diff --git a/js/src/jit/x86/CodeGenerator-x86.cpp b/js/src/jit/x86/CodeGenerator-x86.cpp index 2689f0c14029..52702b4c2f8a 100644 --- a/js/src/jit/x86/CodeGenerator-x86.cpp +++ b/js/src/jit/x86/CodeGenerator-x86.cpp @@ -508,27 +508,55 @@ namespace js { namespace jit { class OutOfLineTruncate : public OutOfLineCodeBase { - LTruncateDToInt32* ins_; + LInstruction* ins_; public: - explicit OutOfLineTruncate(LTruncateDToInt32* ins) : ins_(ins) {} + explicit OutOfLineTruncate(LInstruction* ins) : ins_(ins) { + MOZ_ASSERT(ins_->isTruncateDToInt32() || + ins_->isWasmBuiltinTruncateDToInt32()); + } void accept(CodeGeneratorX86* codegen) override { codegen->visitOutOfLineTruncate(this); } - LTruncateDToInt32* ins() const { return ins_; } + + LAllocation* input() { return ins_->getOperand(0); } + LDefinition* output() { return ins_->getDef(0); } + LDefinition* tempFloat() { return ins_->getTemp(0); } + + wasm::BytecodeOffset bytecodeOffset() const { + if (ins_->isTruncateDToInt32()) { + return ins_->toTruncateDToInt32()->mir()->bytecodeOffset(); + } + + return ins_->toWasmBuiltinTruncateDToInt32()->mir()->bytecodeOffset(); + } }; class OutOfLineTruncateFloat32 : public OutOfLineCodeBase { - LTruncateFToInt32* ins_; + LInstruction* ins_; public: - explicit OutOfLineTruncateFloat32(LTruncateFToInt32* ins) : ins_(ins) {} + explicit OutOfLineTruncateFloat32(LInstruction* ins) : ins_(ins) { + MOZ_ASSERT(ins_->isTruncateFToInt32() || + ins_->isWasmBuiltinTruncateFToInt32()); + } void accept(CodeGeneratorX86* codegen) override { codegen->visitOutOfLineTruncateFloat32(this); } - LTruncateFToInt32* ins() const { return ins_; } + + LAllocation* input() { return ins_->getOperand(0); } + LDefinition* output() { return ins_->getDef(0); } + LDefinition* tempFloat() { return ins_->getTemp(0); } + + wasm::BytecodeOffset bytecodeOffset() const { + if (ins_->isTruncateFToInt32()) { + return ins_->toTruncateDToInt32()->mir()->bytecodeOffset(); + } + + return ins_->toWasmBuiltinTruncateFToInt32()->mir()->bytecodeOffset(); + } }; } // namespace jit @@ -545,6 +573,18 @@ void CodeGenerator::visitTruncateDToInt32(LTruncateDToInt32* ins) { masm.bind(ool->rejoin()); } +void CodeGenerator::visitWasmBuiltinTruncateDToInt32( + LWasmBuiltinTruncateDToInt32* lir) { + FloatRegister input = ToFloatRegister(lir->getOperand(0)); + Register output = ToRegister(lir->getDef(0)); + + OutOfLineTruncate* ool = new (alloc()) OutOfLineTruncate(lir); + addOutOfLineCode(ool, lir->mir()); + + masm.branchTruncateDoubleMaybeModUint32(input, output, ool->entry()); + masm.bind(ool->rejoin()); +} + void CodeGenerator::visitTruncateFToInt32(LTruncateFToInt32* ins) { FloatRegister input = ToFloatRegister(ins->input()); Register output = ToRegister(ins->output()); @@ -556,10 +596,21 @@ void CodeGenerator::visitTruncateFToInt32(LTruncateFToInt32* ins) { masm.bind(ool->rejoin()); } +void CodeGenerator::visitWasmBuiltinTruncateFToInt32( + LWasmBuiltinTruncateFToInt32* lir) { + FloatRegister input = ToFloatRegister(lir->getOperand(0)); + Register output = ToRegister(lir->getDef(0)); + + OutOfLineTruncateFloat32* ool = new (alloc()) OutOfLineTruncateFloat32(lir); + addOutOfLineCode(ool, lir->mir()); + + masm.branchTruncateFloat32MaybeModUint32(input, output, ool->entry()); + masm.bind(ool->rejoin()); +} + void CodeGeneratorX86::visitOutOfLineTruncate(OutOfLineTruncate* ool) { - LTruncateDToInt32* ins = ool->ins(); - FloatRegister input = ToFloatRegister(ins->input()); - Register output = ToRegister(ins->output()); + FloatRegister input = ToFloatRegister(ool->input()); + Register output = ToRegister(ool->output()); Label fail; @@ -584,7 +635,7 @@ void CodeGeneratorX86::visitOutOfLineTruncate(OutOfLineTruncate* ool) { masm.addl(Imm32(sizeof(double)), esp); masm.jump(&fail); } else { - FloatRegister temp = ToFloatRegister(ins->tempFloat()); + FloatRegister temp = ToFloatRegister(ool->tempFloat()); // Try to convert doubles representing integers within 2^32 of a signed // integer, by adding/subtracting 2^32 and then trying to convert to int32. @@ -622,13 +673,20 @@ void CodeGeneratorX86::visitOutOfLineTruncate(OutOfLineTruncate* ool) { masm.bind(&fail); { + if (gen->compilingWasm()) { + masm.Push(WasmTlsReg); + } + int32_t framePushedAfterTls = masm.framePushed(); + saveVolatile(output); if (gen->compilingWasm()) { masm.setupWasmABICall(); masm.passABIArg(input, MoveOp::DOUBLE); - masm.callWithABI(ins->mir()->bytecodeOffset(), - wasm::SymbolicAddress::ToInt32, mozilla::Nothing()); + + int32_t tlsOffset = masm.framePushed() - framePushedAfterTls; + masm.callWithABI(ool->bytecodeOffset(), wasm::SymbolicAddress::ToInt32, + mozilla::Some(tlsOffset)); } else { masm.setupUnalignedABICall(output); masm.passABIArg(input, MoveOp::DOUBLE); @@ -638,6 +696,10 @@ void CodeGeneratorX86::visitOutOfLineTruncate(OutOfLineTruncate* ool) { masm.storeCallInt32Result(output); restoreVolatile(output); + + if (gen->compilingWasm()) { + masm.Pop(WasmTlsReg); + } } masm.jump(ool->rejoin()); @@ -645,9 +707,8 @@ void CodeGeneratorX86::visitOutOfLineTruncate(OutOfLineTruncate* ool) { void CodeGeneratorX86::visitOutOfLineTruncateFloat32( OutOfLineTruncateFloat32* ool) { - LTruncateFToInt32* ins = ool->ins(); - FloatRegister input = ToFloatRegister(ins->input()); - Register output = ToRegister(ins->output()); + FloatRegister input = ToFloatRegister(ool->input()); + Register output = ToRegister(ool->output()); Label fail; @@ -674,7 +735,7 @@ void CodeGeneratorX86::visitOutOfLineTruncateFloat32( masm.addl(Imm32(sizeof(uint64_t)), esp); masm.jump(&fail); } else { - FloatRegister temp = ToFloatRegister(ins->tempFloat()); + FloatRegister temp = ToFloatRegister(ool->tempFloat()); // Try to convert float32 representing integers within 2^32 of a signed // integer, by adding/subtracting 2^32 and then trying to convert to int32. @@ -712,6 +773,11 @@ void CodeGeneratorX86::visitOutOfLineTruncateFloat32( masm.bind(&fail); { + if (gen->compilingWasm()) { + masm.Push(WasmTlsReg); + } + int32_t framePushedAfterTls = masm.framePushed(); + saveVolatile(output); masm.Push(input); @@ -726,8 +792,9 @@ void CodeGeneratorX86::visitOutOfLineTruncateFloat32( masm.passABIArg(input.asDouble(), MoveOp::DOUBLE); if (gen->compilingWasm()) { - masm.callWithABI(ins->mir()->bytecodeOffset(), - wasm::SymbolicAddress::ToInt32, mozilla::Nothing()); + int32_t tlsOffset = masm.framePushed() - framePushedAfterTls; + masm.callWithABI(ool->bytecodeOffset(), wasm::SymbolicAddress::ToInt32, + mozilla::Some(tlsOffset)); } else { masm.callWithABI(BitwiseCast(JS::ToInt32), MoveOp::GENERAL, CheckUnsafeCallWithABI::DontCheckOther); @@ -737,6 +804,10 @@ void CodeGeneratorX86::visitOutOfLineTruncateFloat32( masm.Pop(input); restoreVolatile(output); + + if (gen->compilingWasm()) { + masm.Pop(WasmTlsReg); + } } masm.jump(ool->rejoin()); diff --git a/js/src/wasm/WasmIonCompile.cpp b/js/src/wasm/WasmIonCompile.cpp index fd4e51a6c67e..88b8eb06939f 100644 --- a/js/src/wasm/WasmIonCompile.cpp +++ b/js/src/wasm/WasmIonCompile.cpp @@ -450,13 +450,13 @@ class FunctionCompiler { // Do this for Int32 only since Int64 is not subject to the same // issues. // - // Note the offsets passed to MTruncateToInt32 are wrong here, but - // it doesn't matter: they're not codegen'd to calls since inputs + // Note the offsets passed to MWasmBuiltinTruncateToInt32 are wrong here, + // but it doesn't matter: they're not codegen'd to calls since inputs // already are int32. - auto* lhs2 = MTruncateToInt32::New(alloc(), lhs); + auto* lhs2 = createTruncateToInt32(lhs); curBlock_->add(lhs2); lhs = lhs2; - auto* rhs2 = MTruncateToInt32::New(alloc(), rhs); + auto* rhs2 = createTruncateToInt32(rhs); curBlock_->add(rhs2); rhs = rhs2; } @@ -479,6 +479,15 @@ class FunctionCompiler { return ins; } + MInstruction* createTruncateToInt32(MDefinition* op) { + // See declaration of LWasmBuiltinTruncateFToInt32. + if (op->type() == MIRType::Double || op->type() == MIRType::Float32) { + return MWasmBuiltinTruncateToInt32::New(alloc(), op, tlsPointer_); + } + + return MTruncateToInt32::New(alloc(), op); + } + MDefinition* mod(MDefinition* lhs, MDefinition* rhs, MIRType type, bool unsignd) { if (inDeadCode()) { @@ -487,10 +496,10 @@ class FunctionCompiler { bool trapOnError = !env().isAsmJS(); if (!unsignd && type == MIRType::Int32) { // See block comment in div(). - auto* lhs2 = MTruncateToInt32::New(alloc(), lhs); + auto* lhs2 = createTruncateToInt32(lhs); curBlock_->add(lhs2); lhs = lhs2; - auto* rhs2 = MTruncateToInt32::New(alloc(), rhs); + auto* rhs2 = createTruncateToInt32(rhs); curBlock_->add(rhs2); rhs = rhs2; } @@ -2208,11 +2217,13 @@ MDefinition* FunctionCompiler::unary(MDefinition* op) { } template <> -MDefinition* FunctionCompiler::unary(MDefinition* op) { +MDefinition* FunctionCompiler::unary( + MDefinition* op) { if (inDeadCode()) { return nullptr; } - auto* ins = MTruncateToInt32::New(alloc(), op, bytecodeOffset()); + auto* ins = MWasmBuiltinTruncateToInt32::New(alloc(), op, tlsPointer_, + bytecodeOffset()); curBlock_->add(ins); return ins; } @@ -2778,7 +2789,12 @@ static bool EmitTruncate(FunctionCompiler& f, ValType operandType, } if (resultType == ValType::I32) { if (f.env().isAsmJS()) { - f.iter().setResult(f.unary(input)); + if (input->type() == MIRType::Double || + input->type() == MIRType::Float32) { + f.iter().setResult(f.unary(input)); + } else { + f.iter().setResult(f.unary(input)); + } } else { f.iter().setResult(f.truncate(input, flags)); }