diff --git a/js/src/jit-test/tests/warp/float16-as-float32-specialization-for-float16array-hole.js b/js/src/jit-test/tests/warp/float16-as-float32-specialization-for-float16array-hole.js new file mode 100644 index 0000000000000..2d9cadcc26007 --- /dev/null +++ b/js/src/jit-test/tests/warp/float16-as-float32-specialization-for-float16array-hole.js @@ -0,0 +1,87 @@ +function float32(f16, i, index) { + // Unbox to Int32. + i = i|0; + + // Float32 addition. + let x = Math.fround(i + 0.1); + + // Float32 square root. + let y = Math.fround(Math.sqrt(x)); + + // Store as Float16. + f16[index] = y; +} + +function float64(f16, i, index) { + // Unbox to Int32. + i = i|0; + + // Float32 addition. + let x = Math.fround(i + 0.1); + + // Float64 square root. + let y = Math.sqrt(x); + + // Store as Float16. + f16[index] = y; +} + +function toBaseline(f) { + let source = f.toString(); + assertEq(source.at(-1), "}"); + + // Add with-statement to disable Ion compilation. + source = source.slice(0, -1) + "; with ({}); }"; + + return Function(`return ${source};`)(); +} + +// Different results are expected for these inputs: +// +// Input Float64-SQRT Float32-SQRT +// ----------------------------------- +// 1527 39.09375 39.0625 +// 16464 128.375 128.25 +// 18581 136.375 136.25 +// 20826 144.375 144.25 +// 23199 152.375 152.25 +// 25700 160.375 160.25 +// 28329 168.375 168.25 +// 31086 176.375 176.25 +// +// Limit execution to 1550 to avoid spending too much time on this single test. +// +// 1550 iterations should still be enough to allow tiering up to Ion, at least +// under eager compilation settings. +const LIMIT = 1550; + +let float32_baseline = toBaseline(float32); +let float64_baseline = toBaseline(float64); + +let f16 = new Float16Array(1); +let u16 = new Uint16Array(f16.buffer); + +let n = 0; +for (let i = 0; i < LIMIT; ++i) { + // Call with out-of-bounds indices to trigger compilation with + // MStoreTypedArrayElementHole. + float32(f16, i, 100_000); + float64(f16, i, 100_000); + + float32(f16, i, 0); + let x = u16[0]; + + float32_baseline(f16, i, 0); + assertEq(x, u16[0]); + + float64(f16, i, 0); + let y = u16[0]; + + float64_baseline(f16, i, 0); + assertEq(y, u16[0]); + + if (x !== y) { + n++; + } +} +assertEq(n, 1); diff --git a/js/src/jit-test/tests/warp/float16-as-float32-specialization-for-float16array.js b/js/src/jit-test/tests/warp/float16-as-float32-specialization-for-float16array.js new file mode 100644 index 0000000000000..3e97ca753b6fa --- /dev/null +++ b/js/src/jit-test/tests/warp/float16-as-float32-specialization-for-float16array.js @@ -0,0 +1,82 @@ +function float32(f16, i) { + // Unbox to Int32. + i = i|0; + + // Float32 addition. + let x = Math.fround(i + 0.1); + + // Float32 square root. + let y = Math.fround(Math.sqrt(x)); + + // Store as Float16. + f16[0] = y; +} + +function float64(f16, i) { + // Unbox to Int32. + i = i|0; + + // Float32 addition. + let x = Math.fround(i + 0.1); + + // Float64 square root. + let y = Math.sqrt(x); + + // Store as Float16. + f16[0] = y; +} + +function toBaseline(f) { + let source = f.toString(); + assertEq(source.at(-1), "}"); + + // Add with-statement to disable Ion compilation. + source = source.slice(0, -1) + "; with ({}); }"; + + return Function(`return ${source};`)(); +} + +// Different results are expected for these inputs: +// +// Input Float64-SQRT Float32-SQRT +// ----------------------------------- +// 1527 39.09375 39.0625 +// 16464 128.375 128.25 +// 18581 136.375 136.25 +// 20826 144.375 144.25 +// 23199 152.375 152.25 +// 25700 160.375 160.25 +// 28329 168.375 168.25 +// 31086 176.375 176.25 +// +// Limit execution to 1550 to avoid spending too much time on this single test. +// +// 1550 iterations should still be enough to allow tiering up to Ion, at least +// under eager compilation settings. +const LIMIT = 1550; + +let float32_baseline = toBaseline(float32); +let float64_baseline = toBaseline(float64); + +let f16 = new Float16Array(1); +let u16 = new Uint16Array(f16.buffer); + +let n = 0; +for (let i = 0; i < LIMIT; ++i) { + float32(f16, i); + let x = u16[0]; + + float32_baseline(f16, i); + assertEq(x, u16[0]); + + float64(f16, i); + let y = u16[0]; + + float64_baseline(f16, i); + assertEq(y, u16[0]); + + if (x !== y) { + n++; + } +} +assertEq(n, 1); diff --git a/js/src/jit/ABIFunctionList-inl.h b/js/src/jit/ABIFunctionList-inl.h index d1bc8f0267264..6a0ca3f152e16 100644 --- a/js/src/jit/ABIFunctionList-inl.h +++ b/js/src/jit/ABIFunctionList-inl.h @@ -148,6 +148,7 @@ namespace jit { _(js::jit::EqualStringsHelperPure) \ _(js::jit::FinishBailoutToBaseline) \ _(js::jit::Float16ToFloat32) \ + _(js::jit::Float32ToFloat16) \ _(js::jit::FrameIsDebuggeeCheck) \ _(js::jit::GetContextSensitiveInterpreterStub) \ _(js::jit::GetIndexFromString) \ diff --git a/js/src/jit/ABIFunctionType.yaml b/js/src/jit/ABIFunctionType.yaml index 67deb9490aab1..cc59760aba2c2 100644 --- a/js/src/jit/ABIFunctionType.yaml +++ b/js/src/jit/ABIFunctionType.yaml @@ -55,6 +55,10 @@ ret: General args: [Float32] +# int32_t f(float32) +- ret: Int32 + args: [Float32] + # float f(float) - ret: Float32 args: [Float32] diff --git a/js/src/jit/CacheIR.cpp b/js/src/jit/CacheIR.cpp index 9b9cac524d65a..e7aae6c62bb6d 100644 --- a/js/src/jit/CacheIR.cpp +++ b/js/src/jit/CacheIR.cpp @@ -5126,11 +5126,6 @@ AttachDecision SetPropIRGenerator::tryAttachSetTypedArrayElement( auto* tarr = &obj->as(); Scalar::Type elementType = tarr->type(); - if (elementType == Scalar::Float16) { - // TODO: See Bug 1835034 for JIT support for Float16Array. - return AttachDecision::NoAction; - } - // Don't attach if the input type doesn't match the guard added below. if (!ValueCanConvertToNumeric(elementType, rhsVal_)) { return AttachDecision::NoAction; diff --git a/js/src/jit/CacheIRCompiler.cpp b/js/src/jit/CacheIRCompiler.cpp index 6b101fcb3b801..db9e21c9aa730 100644 --- a/js/src/jit/CacheIRCompiler.cpp +++ b/js/src/jit/CacheIRCompiler.cpp @@ -6611,7 +6611,7 @@ bool CacheIRCompiler::emitStoreTypedArrayElement(ObjOperandId objId, AutoScratchRegister scratch1(allocator, masm); Maybe scratch2; Maybe spectreScratch; - if (Scalar::isBigIntType(elementType) || + if (Scalar::isBigIntType(elementType) || elementType == Scalar::Float16 || viewKind == ArrayBufferViewKind::Resizable) { scratch2.emplace(allocator, masm); } else { @@ -6651,12 +6651,10 @@ bool CacheIRCompiler::emitStoreTypedArrayElement(ObjOperandId objId, #ifndef JS_PUNBOX64 masm.pop(obj); #endif - } else if (elementType == Scalar::Float32) { - ScratchFloat32Scope fpscratch(masm); - masm.convertDoubleToFloat32(floatScratch0, fpscratch); - masm.storeToTypedFloatArray(elementType, fpscratch, dest); - } else if (elementType == Scalar::Float64) { - masm.storeToTypedFloatArray(elementType, floatScratch0, dest); + } else if (Scalar::isFloatingType(elementType)) { + Register temp = scratch2 ? scratch2->get() : InvalidReg; + masm.storeToTypedFloatArray(elementType, floatScratch0, dest, temp, + liveVolatileRegs()); } else { masm.storeToTypedIntArray(elementType, *valInt32, dest); } diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index 475a466bdef96..f3b2dbec1fb89 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -18487,9 +18487,12 @@ template void CodeGenerator::visitOutOfLineSwitch( template static inline void StoreToTypedArray(MacroAssembler& masm, Scalar::Type writeType, - const LAllocation* value, const T& dest) { - if (writeType == Scalar::Float32 || writeType == Scalar::Float64) { - masm.storeToTypedFloatArray(writeType, ToFloatRegister(value), dest); + const LAllocation* value, const T& dest, + Register temp, + LiveRegisterSet volatileRegs) { + if (Scalar::isFloatingType(writeType)) { + masm.storeToTypedFloatArray(writeType, ToFloatRegister(value), dest, temp, + volatileRegs); } else { if (value->isConstant()) { masm.storeToTypedIntArray(writeType, Imm32(ToInt32(value)), dest); @@ -18501,19 +18504,25 @@ static inline void StoreToTypedArray(MacroAssembler& masm, void CodeGenerator::visitStoreUnboxedScalar(LStoreUnboxedScalar* lir) { Register elements = ToRegister(lir->elements()); + Register temp = ToTempRegisterOrInvalid(lir->temp0()); const LAllocation* value = lir->value(); const MStoreUnboxedScalar* mir = lir->mir(); Scalar::Type writeType = mir->writeType(); + LiveRegisterSet volatileRegs; + if (MacroAssembler::StoreRequiresCall(writeType)) { + volatileRegs = liveVolatileRegs(lir); + } + if (lir->index()->isConstant()) { Address dest = ToAddress(elements, lir->index(), writeType); - StoreToTypedArray(masm, writeType, value, dest); + StoreToTypedArray(masm, writeType, value, dest, temp, volatileRegs); } else { BaseIndex dest(elements, ToRegister(lir->index()), ScaleFromScalarType(writeType)); - StoreToTypedArray(masm, writeType, value, dest); + StoreToTypedArray(masm, writeType, value, dest, temp, volatileRegs); } } @@ -18557,7 +18566,9 @@ void CodeGenerator::visitStoreDataViewElement(LStoreDataViewElement* lir) { if (noSwap && (!Scalar::isFloatingType(writeType) || MacroAssembler::SupportsFastUnalignedFPAccesses())) { if (!Scalar::isBigIntType(writeType)) { - StoreToTypedArray(masm, writeType, value, dest); + MOZ_ASSERT(writeType != Scalar::Float16); + StoreToTypedArray(masm, writeType, value, dest, InvalidReg, + LiveRegisterSet{}); } else { masm.loadBigInt64(ToRegister(value), temp64); masm.storeToTypedBigIntArray(writeType, temp64, dest); @@ -18671,17 +18682,22 @@ void CodeGenerator::visitStoreTypedArrayElementHole( Register index = ToRegister(lir->index()); const LAllocation* length = lir->length(); - Register spectreTemp = ToTempRegisterOrInvalid(lir->temp0()); + Register temp = ToTempRegisterOrInvalid(lir->temp0()); + + LiveRegisterSet volatileRegs; + if (MacroAssembler::StoreRequiresCall(arrayType)) { + volatileRegs = liveVolatileRegs(lir); + } Label skip; if (length->isRegister()) { - masm.spectreBoundsCheckPtr(index, ToRegister(length), spectreTemp, &skip); + masm.spectreBoundsCheckPtr(index, ToRegister(length), temp, &skip); } else { - masm.spectreBoundsCheckPtr(index, ToAddress(length), spectreTemp, &skip); + masm.spectreBoundsCheckPtr(index, ToAddress(length), temp, &skip); } BaseIndex dest(elements, index, ScaleFromScalarType(arrayType)); - StoreToTypedArray(masm, arrayType, value, dest); + StoreToTypedArray(masm, arrayType, value, dest, temp, volatileRegs); masm.bind(&skip); } diff --git a/js/src/jit/LIROps.yaml b/js/src/jit/LIROps.yaml index d92f8620c444c..90eb5a9b82581 100644 --- a/js/src/jit/LIROps.yaml +++ b/js/src/jit/LIROps.yaml @@ -2169,6 +2169,7 @@ elements: WordSized index: WordSized value: WordSized + num_temps: 1 mir_op: true - name: StoreUnboxedBigInt diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp index 9b4bfd11b83f0..1c2ffd24e857a 100644 --- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -4718,6 +4718,8 @@ void LIRGenerator::visitStoreUnboxedScalar(MStoreUnboxedScalar* ins) { MOZ_ASSERT(ins->index()->type() == MIRType::IntPtr); if (ins->isFloatWrite()) { + MOZ_ASSERT_IF(ins->writeType() == Scalar::Float16, + ins->value()->type() == MIRType::Float32); MOZ_ASSERT_IF(ins->writeType() == Scalar::Float32, ins->value()->type() == MIRType::Float32); MOZ_ASSERT_IF(ins->writeType() == Scalar::Float64, @@ -4761,7 +4763,19 @@ void LIRGenerator::visitStoreUnboxedScalar(MStoreUnboxedScalar* ins) { add(fence, ins); } if (!ins->isBigIntWrite()) { - add(new (alloc()) LStoreUnboxedScalar(elements, index, value), ins); + // We need a temp register for Float16Array. + LDefinition tempDef = LDefinition::BogusTemp(); + if (ins->writeType() == Scalar::Float16) { + tempDef = temp(); + } + + auto* lir = + new (alloc()) LStoreUnboxedScalar(elements, index, value, tempDef); + add(lir, ins); + + if (MacroAssembler::StoreRequiresCall(ins->writeType())) { + assignSafepoint(lir, ins); + } } else { add(new (alloc()) LStoreUnboxedBigInt(elements, index, value, tempInt64()), ins); @@ -4818,6 +4832,8 @@ void LIRGenerator::visitStoreTypedArrayElementHole( MOZ_ASSERT(ins->length()->type() == MIRType::IntPtr); if (ins->isFloatWrite()) { + MOZ_ASSERT_IF(ins->arrayType() == Scalar::Float16, + ins->value()->type() == MIRType::Float32); MOZ_ASSERT_IF(ins->arrayType() == Scalar::Float32, ins->value()->type() == MIRType::Float32); MOZ_ASSERT_IF(ins->arrayType() == Scalar::Float64, @@ -4843,11 +4859,18 @@ void LIRGenerator::visitStoreTypedArrayElementHole( } if (!ins->isBigIntWrite()) { - LDefinition spectreTemp = - BoundsCheckNeedsSpectreTemp() ? temp() : LDefinition::BogusTemp(); - auto* lir = new (alloc()) LStoreTypedArrayElementHole( - elements, length, index, value, spectreTemp); + LDefinition tempDef = LDefinition::BogusTemp(); + if (BoundsCheckNeedsSpectreTemp() || ins->arrayType() == Scalar::Float16) { + tempDef = temp(); + } + + auto* lir = new (alloc()) + LStoreTypedArrayElementHole(elements, length, index, value, tempDef); add(lir, ins); + + if (MacroAssembler::StoreRequiresCall(ins->arrayType())) { + assignSafepoint(lir, ins); + } } else { auto* lir = new (alloc()) LStoreTypedArrayElementHoleBigInt( elements, length, index, value, tempInt64()); diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index 6262b81e1bff1..62e3bb1e61814 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -6814,7 +6814,8 @@ class StoreUnboxedScalarBase { writeType_ == Scalar::Uint32; } bool isFloatWrite() const { - return writeType_ == Scalar::Float32 || writeType_ == Scalar::Float64; + return writeType_ == Scalar::Float16 || writeType_ == Scalar::Float32 || + writeType_ == Scalar::Float64; } bool isBigIntWrite() const { return Scalar::isBigIntType(writeType_); } }; @@ -6855,6 +6856,15 @@ class MStoreUnboxedScalar : public MTernaryInstruction, return use == getUseFor(2) && writeType() == Scalar::Float32; } +#ifdef DEBUG + // Float16 inputs are typed as float32, but this instruction can NOT consume + // float32 when its write-type is float16. + bool isConsistentFloat32Use(MUse* use) const override { + return use == getUseFor(2) && + (writeType() == Scalar::Float32 || writeType() == Scalar::Float16); + } +#endif + ALLOW_CLONE(MStoreUnboxedScalar) }; @@ -6920,6 +6930,15 @@ class MStoreTypedArrayElementHole : public MQuaternaryInstruction, return use == getUseFor(3) && arrayType() == Scalar::Float32; } +#ifdef DEBUG + // Float16 inputs are typed as float32, but this instruction can NOT consume + // float32 when its array-type is float16. + bool isConsistentFloat32Use(MUse* use) const override { + return use == getUseFor(3) && + (arrayType() == Scalar::Float32 || arrayType() == Scalar::Float16); + } +#endif + ALLOW_CLONE(MStoreTypedArrayElementHole) }; diff --git a/js/src/jit/MacroAssembler-inl.h b/js/src/jit/MacroAssembler-inl.h index e5dcd70cb658b..a022ee13ae8bd 100644 --- a/js/src/jit/MacroAssembler-inl.h +++ b/js/src/jit/MacroAssembler-inl.h @@ -195,6 +195,7 @@ ABIFunctionType MacroAssembler::signature() const { case Args_Float32_General: case Args_Float32_Int32: case Args_Int_Float32: + case Args_Int32_Float32: case Args_Double_Double: case Args_Double_Int: case Args_Double_DoubleInt: diff --git a/js/src/jit/MacroAssembler.cpp b/js/src/jit/MacroAssembler.cpp index bc39513643cc9..605e43700ca89 100644 --- a/js/src/jit/MacroAssembler.cpp +++ b/js/src/jit/MacroAssembler.cpp @@ -70,14 +70,28 @@ TrampolinePtr MacroAssembler::preBarrierTrampoline(MIRType type) { return rt->preBarrier(type); } -template -static void StoreToTypedFloatArray(MacroAssembler& masm, int arrayType, - const S& value, const T& dest) { +template +static void StoreToTypedFloatArray(MacroAssembler& masm, Scalar::Type arrayType, + FloatRegister value, const T& dest, + Register temp, + LiveRegisterSet volatileLiveRegs) { switch (arrayType) { - case Scalar::Float32: - masm.storeFloat32(value, dest); + case Scalar::Float16: + masm.storeFloat16(value, dest, temp, volatileLiveRegs); + break; + case Scalar::Float32: { + if (value.isDouble()) { + ScratchFloat32Scope fpscratch(masm); + masm.convertDoubleToFloat32(value, fpscratch); + masm.storeFloat32(fpscratch, dest); + } else { + MOZ_ASSERT(value.isSingle()); + masm.storeFloat32(value, dest); + } break; + } case Scalar::Float64: + MOZ_ASSERT(value.isDouble()); masm.storeDouble(value, dest); break; default: @@ -87,13 +101,16 @@ static void StoreToTypedFloatArray(MacroAssembler& masm, int arrayType, void MacroAssembler::storeToTypedFloatArray(Scalar::Type arrayType, FloatRegister value, - const BaseIndex& dest) { - StoreToTypedFloatArray(*this, arrayType, value, dest); + const BaseIndex& dest, + Register temp, + LiveRegisterSet volatileLiveRegs) { + StoreToTypedFloatArray(*this, arrayType, value, dest, temp, volatileLiveRegs); } void MacroAssembler::storeToTypedFloatArray(Scalar::Type arrayType, FloatRegister value, - const Address& dest) { - StoreToTypedFloatArray(*this, arrayType, value, dest); + const Address& dest, Register temp, + LiveRegisterSet volatileLiveRegs) { + StoreToTypedFloatArray(*this, arrayType, value, dest, temp, volatileLiveRegs); } template @@ -7702,6 +7719,58 @@ template void MacroAssembler::loadFloat16(const BaseIndex& src, Register temp2, LiveRegisterSet volatileLiveRegs); +template +void MacroAssembler::storeFloat16(FloatRegister src, const T& dest, + Register temp, + LiveRegisterSet volatileLiveRegs) { + ScratchFloat32Scope fpscratch(*this); + + if (src.isDouble()) { + if (MacroAssembler::SupportsFloat64To16()) { + canonicalizeDoubleIfDeterministic(src); + convertDoubleToFloat16(src, fpscratch); + storeUncanonicalizedFloat16(fpscratch, dest, temp); + return; + } + + convertDoubleToFloat16(src, fpscratch, temp, volatileLiveRegs); + src = fpscratch; + } + MOZ_ASSERT(src.isSingle()); + + if (MacroAssembler::SupportsFloat32To16()) { + canonicalizeFloatIfDeterministic(src); + convertFloat32ToFloat16(src, fpscratch); + storeUncanonicalizedFloat16(fpscratch, dest, temp); + return; + } + + canonicalizeFloatIfDeterministic(src); + + LiveRegisterSet save = volatileLiveRegs; + save.takeUnchecked(temp); + + PushRegsInMask(save); + + using Fn = int32_t (*)(float); + setupUnalignedABICall(temp); + passABIArg(src, ABIType::Float32); + callWithABI(); + storeCallInt32Result(temp); + + PopRegsInMask(save); + + store16(temp, dest); +} + +template void MacroAssembler::storeFloat16(FloatRegister src, + const Address& dest, Register temp, + LiveRegisterSet volatileLiveRegs); + +template void MacroAssembler::storeFloat16(FloatRegister src, + const BaseIndex& dest, Register temp, + LiveRegisterSet volatileLiveRegs); + void MacroAssembler::moveGPRToFloat16(Register src, FloatRegister dest, Register temp, LiveRegisterSet volatileLiveRegs) { diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h index ed3c6f6a8e945..018496349fb28 100644 --- a/js/src/jit/MacroAssembler.h +++ b/js/src/jit/MacroAssembler.h @@ -2263,6 +2263,15 @@ class MacroAssembler : public MacroAssemblerSpecific { template inline FaultingCodeOffset storeFloat32(FloatRegister src, const T& dest); + inline FaultingCodeOffset storeUncanonicalizedFloat16(FloatRegister src, + const Address& dest, + Register scratch) + DEFINED_ON(x86_shared, arm, arm64, mips_shared, loong64, riscv64, wasm32); + inline FaultingCodeOffset storeUncanonicalizedFloat16(FloatRegister src, + const BaseIndex& dest, + Register scratch) + DEFINED_ON(x86_shared, arm, arm64, mips_shared, loong64, riscv64, wasm32); + template void storeUnboxedValue(const ConstantOrRegister& value, MIRType valueType, const T& dest) PER_ARCH; @@ -5224,6 +5233,10 @@ class MacroAssembler : public MacroAssemblerSpecific { return type == Scalar::Float16 && !MacroAssembler::SupportsFloat32To16(); } + static bool StoreRequiresCall(Scalar::Type type) { + return type == Scalar::Float16 && !MacroAssembler::SupportsFloat32To16(); + } + template void loadFromTypedArray(Scalar::Type arrayType, const T& src, AnyRegister dest, Register temp1, Register temp2, @@ -5262,9 +5275,11 @@ class MacroAssembler : public MacroAssemblerSpecific { } void storeToTypedFloatArray(Scalar::Type arrayType, FloatRegister value, - const BaseIndex& dest); + const BaseIndex& dest, Register temp, + LiveRegisterSet volatileLiveRegs); void storeToTypedFloatArray(Scalar::Type arrayType, FloatRegister value, - const Address& dest); + const Address& dest, Register temp, + LiveRegisterSet volatileLiveRegs); void storeToTypedBigIntArray(Scalar::Type arrayType, Register64 value, const BaseIndex& dest); @@ -5292,6 +5307,10 @@ class MacroAssembler : public MacroAssemblerSpecific { void loadFloat16(const T& src, FloatRegister dest, Register temp1, Register temp2, LiveRegisterSet volatileLiveRegs); + template + void storeFloat16(FloatRegister src, const T& dest, Register temp, + LiveRegisterSet volatileLiveRegs); + void moveGPRToFloat16(Register src, FloatRegister dest, Register temp, LiveRegisterSet volatileLiveRegs); diff --git a/js/src/jit/TypePolicy.cpp b/js/src/jit/TypePolicy.cpp index bd03a475ae348..b969ab888db55 100644 --- a/js/src/jit/TypePolicy.cpp +++ b/js/src/jit/TypePolicy.cpp @@ -905,6 +905,10 @@ bool StoreUnboxedScalarPolicy::adjustValueInput(TempAllocator& alloc, // The transpiler should have inserted MClampToUint8. MOZ_ASSERT(value->type() == MIRType::Int32); break; + case Scalar::Float16: + value = MToFloat16::New(alloc, value); + ins->block()->insertBefore(ins, value->toInstruction()); + break; case Scalar::Float32: if (value->type() != MIRType::Float32) { value = MToFloat32::New(alloc, value); diff --git a/js/src/jit/VMFunctions.cpp b/js/src/jit/VMFunctions.cpp index 3d9b1d5c47451..be4448f273992 100644 --- a/js/src/jit/VMFunctions.cpp +++ b/js/src/jit/VMFunctions.cpp @@ -3087,6 +3087,11 @@ float Float16ToFloat32(int32_t value) { return f16.toFloat(); } +int32_t Float32ToFloat16(float value) { + AutoUnsafeCallWithABI unsafe; + return static_cast(js::float16{value}.val); +} + JSAtom* AtomizeStringNoGC(JSContext* cx, JSString* str) { // IC code calls this directly so we shouldn't GC. AutoUnsafeCallWithABI unsafe; diff --git a/js/src/jit/VMFunctions.h b/js/src/jit/VMFunctions.h index c6c2c55e592bb..3df1e1367dff8 100644 --- a/js/src/jit/VMFunctions.h +++ b/js/src/jit/VMFunctions.h @@ -693,6 +693,7 @@ float RoundFloat16ToFloat32(float d); float RoundFloat16ToFloat32(double d); float Float16ToFloat32(int32_t value); +int32_t Float32ToFloat16(float value); JSAtom* AtomizeStringNoGC(JSContext* cx, JSString* str); diff --git a/js/src/jit/arm/MacroAssembler-arm-inl.h b/js/src/jit/arm/MacroAssembler-arm-inl.h index c411b168e7cc5..07b5e70ff4b55 100644 --- a/js/src/jit/arm/MacroAssembler-arm-inl.h +++ b/js/src/jit/arm/MacroAssembler-arm-inl.h @@ -2537,6 +2537,15 @@ FaultingCodeOffset MacroAssembler::storeUncanonicalizedFloat32( return FaultingCodeOffset(offset.getOffset()); } +FaultingCodeOffset MacroAssembler::storeUncanonicalizedFloat16( + FloatRegister src, const Address& dest, Register) { + MOZ_CRASH("Not supported for this target"); +} +FaultingCodeOffset MacroAssembler::storeUncanonicalizedFloat16( + FloatRegister src, const BaseIndex& dest, Register) { + MOZ_CRASH("Not supported for this target"); +} + void MacroAssembler::memoryBarrier(MemoryBarrierBits barrier) { // On ARMv6 the optional argument (BarrierST, etc) is ignored. if (barrier == (MembarStoreStore | MembarSynchronizing)) { diff --git a/js/src/jit/arm64/MacroAssembler-arm64-inl.h b/js/src/jit/arm64/MacroAssembler-arm64-inl.h index f86579e84209c..b4333cf0c6a06 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64-inl.h +++ b/js/src/jit/arm64/MacroAssembler-arm64-inl.h @@ -2245,6 +2245,15 @@ FaultingCodeOffset MacroAssembler::storeUncanonicalizedFloat32( return doBaseIndex(ARMFPRegister(src, 32), addr, vixl::STR_s); } +FaultingCodeOffset MacroAssembler::storeUncanonicalizedFloat16( + FloatRegister src, const Address& dest, Register) { + return Str(ARMFPRegister(src, 16), toMemOperand(dest)); +} +FaultingCodeOffset MacroAssembler::storeUncanonicalizedFloat16( + FloatRegister src, const BaseIndex& dest, Register) { + return doBaseIndex(ARMFPRegister(src, 16), dest, vixl::STR_h); +} + void MacroAssembler::memoryBarrier(MemoryBarrierBits barrier) { // Bug 1715494: Discriminating barriers such as StoreStore are hard to reason // about. Execute the full barrier for everything that requires a barrier. diff --git a/js/src/jit/loong64/MacroAssembler-loong64-inl.h b/js/src/jit/loong64/MacroAssembler-loong64-inl.h index 11bf1948bc115..76b4ca55f9612 100644 --- a/js/src/jit/loong64/MacroAssembler-loong64-inl.h +++ b/js/src/jit/loong64/MacroAssembler-loong64-inl.h @@ -2017,6 +2017,15 @@ FaultingCodeOffset MacroAssembler::storeUncanonicalizedDouble( return ma_fst_d(src, addr); } +FaultingCodeOffset MacroAssembler::storeUncanonicalizedFloat16( + FloatRegister src, const Address& dest, Register) { + MOZ_CRASH("Not supported for this target"); +} +FaultingCodeOffset MacroAssembler::storeUncanonicalizedFloat16( + FloatRegister src, const BaseIndex& dest, Register) { + MOZ_CRASH("Not supported for this target"); +} + void MacroAssembler::memoryBarrier(MemoryBarrierBits barrier) { if (barrier) { as_dbar(0); diff --git a/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h b/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h index d00e559895760..3425a4659cb79 100644 --- a/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h +++ b/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h @@ -1304,6 +1304,15 @@ FaultingCodeOffset MacroAssembler::storeUncanonicalizedFloat32( ma_ss(src, addr); } +FaultingCodeOffset MacroAssembler::storeUncanonicalizedFloat16( + FloatRegister src, const Address& dest, Register) { + MOZ_CRASH("Not supported for this target"); +} +FaultingCodeOffset MacroAssembler::storeUncanonicalizedFloat16( + FloatRegister src, const BaseIndex& dest, Register) { + MOZ_CRASH("Not supported for this target"); +} + void MacroAssembler::memoryBarrier(MemoryBarrierBits barrier) { if (barrier) { as_sync(); diff --git a/js/src/jit/riscv64/MacroAssembler-riscv64-inl.h b/js/src/jit/riscv64/MacroAssembler-riscv64-inl.h index 0d33e92f4eb9e..2152502aa84aa 100644 --- a/js/src/jit/riscv64/MacroAssembler-riscv64-inl.h +++ b/js/src/jit/riscv64/MacroAssembler-riscv64-inl.h @@ -1915,6 +1915,16 @@ void MacroAssembler::sqrtDouble(FloatRegister src, FloatRegister dest) { void MacroAssembler::sqrtFloat32(FloatRegister src, FloatRegister dest) { fsqrt_s(dest, src); } + +FaultingCodeOffset MacroAssembler::storeUncanonicalizedFloat16( + FloatRegister src, const Address& dest, Register) { + MOZ_CRASH("Not supported for this target"); +} +FaultingCodeOffset MacroAssembler::storeUncanonicalizedFloat16( + FloatRegister src, const BaseIndex& dest, Register) { + MOZ_CRASH("Not supported for this target"); +} + FaultingCodeOffset MacroAssembler::storeUncanonicalizedFloat32( FloatRegister src, const Address& addr) { return ma_fst_s(src, addr); diff --git a/js/src/jit/wasm32/MacroAssembler-wasm32-inl.h b/js/src/jit/wasm32/MacroAssembler-wasm32-inl.h index cbd6b75a9c8fb..0c8e8c645398e 100644 --- a/js/src/jit/wasm32/MacroAssembler-wasm32-inl.h +++ b/js/src/jit/wasm32/MacroAssembler-wasm32-inl.h @@ -834,6 +834,15 @@ FaultingCodeOffset MacroAssembler::storeUncanonicalizedFloat32( MOZ_CRASH(); } +FaultingCodeOffset MacroAssembler::storeUncanonicalizedFloat16( + FloatRegister src, const Address& dest, Register) { + MOZ_CRASH(); +} +FaultingCodeOffset MacroAssembler::storeUncanonicalizedFloat16( + FloatRegister src, const BaseIndex& dest, Register) { + MOZ_CRASH(); +} + void MacroAssembler::addPtr(Imm32 imm, const Address& dest) { MOZ_CRASH(); } void MacroAssembler::addPtr(const Address& src, Register dest) { MOZ_CRASH(); } diff --git a/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h b/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h index 25b1ed0335c38..934bf92ff2084 100644 --- a/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h +++ b/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h @@ -1251,6 +1251,23 @@ FaultingCodeOffset MacroAssembler::storeUncanonicalizedFloat32( template FaultingCodeOffset MacroAssembler::storeFloat32(FloatRegister src, const Operand& dest); +FaultingCodeOffset MacroAssembler::storeUncanonicalizedFloat16( + FloatRegister src, const Address& dest, Register scratch) { + vmovd(src, scratch); + + FaultingCodeOffset fco = FaultingCodeOffset(currentOffset()); + movw(scratch, Operand(dest)); + return fco; +} +FaultingCodeOffset MacroAssembler::storeUncanonicalizedFloat16( + FloatRegister src, const BaseIndex& dest, Register scratch) { + vmovd(src, scratch); + + FaultingCodeOffset fco = FaultingCodeOffset(currentOffset()); + movw(scratch, Operand(dest)); + return fco; +} + void MacroAssembler::memoryBarrier(MemoryBarrierBits barrier) { if (barrier & MembarStoreLoad) { // This implementation follows Linux.