diff --git a/JSTests/stress/ftl-get-by-val-ic-typed-array-float-load-clobbers-fp-temp-register.js b/JSTests/stress/ftl-get-by-val-ic-typed-array-float-load-clobbers-fp-temp-register.js new file mode 100644 index 000000000000..269bde9aa54b --- /dev/null +++ b/JSTests/stress/ftl-get-by-val-ic-typed-array-float-load-clobbers-fp-temp-register.js @@ -0,0 +1,38 @@ +//@ runDefault("--useConcurrentJIT=0") +// The IndexedTypedArrayFloat{16,32,64}Load inline cache stubs call AssemblyHelpers::purifyNaN(), +// which materializes PNaN in MacroAssembler::fpTempRegister (xmm15 on x86-64, q31 on ARM64). +// FTL lets Air allocate that register, so a double that is live across a generic GetByVal +// patchpoint could be silently replaced with NaN once the IC attached a typed-array load case. + +function f(arr, idx, d) { + // Enough doubles live across the access that Air has to use every FP register, including fpTempRegister. + const a0 = d + 0.5, a1 = d + 1.5, a2 = d + 2.5, a3 = d + 3.5, a4 = d + 4.5, a5 = d + 5.5, a6 = d + 6.5, a7 = d + 7.5; + const b0 = d * 0.5, b1 = d * 1.5, b2 = d * 2.5, b3 = d * 3.5, b4 = d * 4.5, b5 = d * 5.5, b6 = d * 6.5, b7 = d * 7.5; + const x = arr[idx]; + return x + a0 * b0 + a1 * b1 + a2 * b2 + a3 * b3 + a4 * b4 + a5 * b5 + a6 * b6 + a7 * b7 + (a0 + a1 + a2 + a3 + a4 + a5 + a6 + a7) - (b0 + b1 + b2 + b3 + b4 + b5 + b6 + b7); +} +noInline(f); + +function expected(idx, d) { + const a0 = d + 0.5, a1 = d + 1.5, a2 = d + 2.5, a3 = d + 3.5, a4 = d + 4.5, a5 = d + 5.5, a6 = d + 6.5, a7 = d + 7.5; + const b0 = d * 0.5, b1 = d * 1.5, b2 = d * 2.5, b3 = d * 3.5, b4 = d * 4.5, b5 = d * 5.5, b6 = d * 6.5, b7 = d * 7.5; + return (idx + 0.25) + a0 * b0 + a1 * b1 + a2 * b2 + a3 * b3 + a4 * b4 + a5 * b5 + a6 * b6 + a7 * b7 + (a0 + a1 + a2 + a3 + a4 + a5 + a6 + a7) - (b0 + b1 + b2 + b3 + b4 + b5 + b6 + b7); +} +noInline(expected); +noFTL(expected); + +for (const TypedArray of [Float64Array, Float32Array, Float16Array]) { + const ta = new TypedArray(8); + for (let i = 0; i < 8; i++) + ta[i] = i + 0.25; + const other = { 0: 0.25, 1: 1.25, 2: 2.25, 3: 3.25, 4: 4.25, 5: 5.25, 6: 6.25, 7: 7.25 }; + for (let i = 0; i < 200000; i++) { + const arr = (i & 1023) === 0 ? other : ta; // keep the GetByVal generic so it goes through an IC + const idx = i & 7; + const d = (i % 97) * 0.25; + const r = f(arr, idx, d); + const e = expected(idx, d); + if (r !== e) + throw new Error(TypedArray.name + ": i=" + i + " got " + r + " expected " + e); + } +} diff --git a/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp b/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp index 199c2beeecdf..baca4cf21877 100644 --- a/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp +++ b/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp @@ -2927,6 +2927,7 @@ class LowerDFGToB3 { RefPtr exceptionHandle = preparePatchpointForExceptions(patchpoint); patchpoint->numGPScratchRegisters = 1; patchpoint->clobber(RegisterSet::macroClobberedGPRs()); + patchpoint->clobber(RegisterSet::macroClobberedFPRs()); State* state = &m_ftlState; CodeOrigin semanticNodeOrigin = node->origin.semantic; patchpoint->setGenerator( @@ -3034,6 +3035,7 @@ class LowerDFGToB3 { patchpoint->numGPScratchRegisters = 1; patchpoint->numFPScratchRegisters = 2; patchpoint->clobber(RegisterSet::macroClobberedGPRs()); + patchpoint->clobber(RegisterSet::macroClobberedFPRs()); State* state = &m_ftlState; CodeOrigin semanticNodeOrigin = node->origin.semantic; patchpoint->setGenerator( @@ -4531,6 +4533,7 @@ class LowerDFGToB3 { patchpoint->append(m_notCellMask, ValueRep::lateReg(GPRInfo::notCellMaskRegister)); patchpoint->append(m_numberTag, ValueRep::lateReg(GPRInfo::numberTagRegister)); patchpoint->clobber(RegisterSet::macroClobberedGPRs()); + patchpoint->clobber(RegisterSet::macroClobberedFPRs()); patchpoint->numGPScratchRegisters = 4; RefPtr exceptionHandle = preparePatchpointForExceptions(patchpoint); @@ -4611,6 +4614,7 @@ class LowerDFGToB3 { patchpoint->append(m_notCellMask, ValueRep::lateReg(GPRInfo::notCellMaskRegister)); patchpoint->append(m_numberTag, ValueRep::lateReg(GPRInfo::numberTagRegister)); patchpoint->clobber(RegisterSet::macroClobberedGPRs()); + patchpoint->clobber(RegisterSet::macroClobberedFPRs()); patchpoint->numGPScratchRegisters = 4; RefPtr exceptionHandle = preparePatchpointForExceptions(patchpoint); @@ -4710,6 +4714,7 @@ class LowerDFGToB3 { patchpoint->append(m_notCellMask, ValueRep::lateReg(GPRInfo::notCellMaskRegister)); patchpoint->append(m_numberTag, ValueRep::lateReg(GPRInfo::numberTagRegister)); patchpoint->clobber(RegisterSet::macroClobberedGPRs()); + patchpoint->clobber(RegisterSet::macroClobberedFPRs()); patchpoint->numGPScratchRegisters = 3; RefPtr exceptionHandle = preparePatchpointForExceptions(patchpoint); @@ -4785,6 +4790,7 @@ class LowerDFGToB3 { patchpoint->append(m_notCellMask, ValueRep::lateReg(GPRInfo::notCellMaskRegister)); patchpoint->append(m_numberTag, ValueRep::lateReg(GPRInfo::numberTagRegister)); patchpoint->clobber(RegisterSet::macroClobberedGPRs()); + patchpoint->clobber(RegisterSet::macroClobberedFPRs()); patchpoint->numGPScratchRegisters = Options::useHandlerICInFTL() ? 1 : 0; RefPtr exceptionHandle = preparePatchpointForExceptions(patchpoint); @@ -4877,6 +4883,7 @@ class LowerDFGToB3 { patchpoint->append(m_notCellMask, ValueRep::lateReg(GPRInfo::notCellMaskRegister)); patchpoint->append(m_numberTag, ValueRep::lateReg(GPRInfo::numberTagRegister)); patchpoint->clobber(RegisterSet::macroClobberedGPRs()); + patchpoint->clobber(RegisterSet::macroClobberedFPRs()); patchpoint->numGPScratchRegisters = 4; RefPtr exceptionHandle = preparePatchpointForExceptions(patchpoint); @@ -4941,6 +4948,7 @@ class LowerDFGToB3 { patchpoint->append(m_notCellMask, ValueRep::lateReg(GPRInfo::notCellMaskRegister)); patchpoint->append(m_numberTag, ValueRep::lateReg(GPRInfo::numberTagRegister)); patchpoint->clobber(RegisterSet::macroClobberedGPRs()); + patchpoint->clobber(RegisterSet::macroClobberedFPRs()); patchpoint->numGPScratchRegisters = Options::useHandlerICInFTL() ? 1 : 0; RefPtr exceptionHandle = preparePatchpointForExceptions(patchpoint); @@ -5085,6 +5093,7 @@ class LowerDFGToB3 { patchpoint->append(m_notCellMask, ValueRep::lateReg(GPRInfo::notCellMaskRegister)); patchpoint->append(m_numberTag, ValueRep::lateReg(GPRInfo::numberTagRegister)); patchpoint->clobber(RegisterSet::macroClobberedGPRs()); + patchpoint->clobber(RegisterSet::macroClobberedFPRs()); patchpoint->numGPScratchRegisters = Options::useHandlerICInFTL() ? 1 : 0; RefPtr exceptionHandle = preparePatchpointForExceptions(patchpoint); @@ -5233,6 +5242,7 @@ class LowerDFGToB3 { patchpoint->append(m_notCellMask, ValueRep::lateReg(GPRInfo::notCellMaskRegister)); patchpoint->append(m_numberTag, ValueRep::lateReg(GPRInfo::numberTagRegister)); patchpoint->clobber(RegisterSet::macroClobberedGPRs()); + patchpoint->clobber(RegisterSet::macroClobberedFPRs()); patchpoint->numGPScratchRegisters = 4; RefPtr exceptionHandle = preparePatchpointForExceptions(patchpoint); @@ -5330,6 +5340,7 @@ class LowerDFGToB3 { patchpoint->append(m_notCellMask, ValueRep::lateReg(GPRInfo::notCellMaskRegister)); patchpoint->append(m_numberTag, ValueRep::lateReg(GPRInfo::numberTagRegister)); patchpoint->clobber(RegisterSet::macroClobberedGPRs()); + patchpoint->clobber(RegisterSet::macroClobberedFPRs()); patchpoint->numGPScratchRegisters = Options::useHandlerICInFTL() ? 1 : 0; RefPtr exceptionHandle = preparePatchpointForExceptions(patchpoint); @@ -5703,6 +5714,7 @@ class LowerDFGToB3 { patchpoint->append(m_notCellMask, ValueRep::reg(GPRInfo::notCellMaskRegister)); patchpoint->append(m_numberTag, ValueRep::reg(GPRInfo::numberTagRegister)); patchpoint->clobber(RegisterSet::macroClobberedGPRs()); + patchpoint->clobber(RegisterSet::macroClobberedFPRs()); patchpoint->numGPScratchRegisters = Options::useHandlerICInFTL() ? 3 : 0; // FIXME: If this is a PutByIdFlush, we might want to late-clobber volatile registers. @@ -5806,6 +5818,7 @@ class LowerDFGToB3 { patchpoint->append(m_notCellMask, ValueRep::lateReg(GPRInfo::notCellMaskRegister)); patchpoint->append(m_numberTag, ValueRep::lateReg(GPRInfo::numberTagRegister)); patchpoint->clobber(RegisterSet::macroClobberedGPRs()); + patchpoint->clobber(RegisterSet::macroClobberedFPRs()); patchpoint->numGPScratchRegisters = 3; RefPtr exceptionHandle = preparePatchpointForExceptions(patchpoint); @@ -5968,6 +5981,7 @@ class LowerDFGToB3 { #endif patchpoint->appendSomeRegister(base); patchpoint->clobber(RegisterSet::macroClobberedGPRs()); + patchpoint->clobber(RegisterSet::macroClobberedFPRs()); patchpoint->numGPScratchRegisters = 2; patchpoint->setGenerator([=] (CCallHelpers& jit, const StackmapGenerationParams& params) { @@ -6166,6 +6180,7 @@ IGNORE_CLANG_WARNINGS_END if (typedArrayType.has_value() && typedArrayType.value() == TypeDataView) { patchpoint->appendSomeRegister(base); patchpoint->clobber(RegisterSet::macroClobberedGPRs()); + patchpoint->clobber(RegisterSet::macroClobberedFPRs()); patchpoint->numGPScratchRegisters = 3; unsigned osrExitArgumentOffset = patchpoint->numChildren() + /* result */ 1; @@ -6201,6 +6216,7 @@ IGNORE_CLANG_WARNINGS_END patchpoint->appendSomeRegister(base); patchpoint->clobber(RegisterSet::macroClobberedGPRs()); + patchpoint->clobber(RegisterSet::macroClobberedFPRs()); patchpoint->numGPScratchRegisters = 2; patchpoint->setGenerator([=] (CCallHelpers& jit, const StackmapGenerationParams& params) { JIT_COMMENT(jit, "typedArrayLength"); @@ -6667,6 +6683,7 @@ IGNORE_CLANG_WARNINGS_END patchpoint->append(m_notCellMask, ValueRep::lateReg(GPRInfo::notCellMaskRegister)); patchpoint->append(m_numberTag, ValueRep::lateReg(GPRInfo::numberTagRegister)); patchpoint->clobber(RegisterSet::macroClobberedGPRs()); + patchpoint->clobber(RegisterSet::macroClobberedFPRs()); patchpoint->numGPScratchRegisters = Options::useHandlerICInFTL() ? 1 : 0; RefPtr exceptionHandle = preparePatchpointForExceptions(patchpoint); @@ -7397,6 +7414,7 @@ IGNORE_CLANG_WARNINGS_END patchpoint->append(m_notCellMask, ValueRep::lateReg(GPRInfo::notCellMaskRegister)); patchpoint->append(m_numberTag, ValueRep::lateReg(GPRInfo::numberTagRegister)); patchpoint->clobber(RegisterSet::macroClobberedGPRs()); + patchpoint->clobber(RegisterSet::macroClobberedFPRs()); patchpoint->numGPScratchRegisters = Options::useHandlerICInFTL() ? 1 : 0; RefPtr exceptionHandle = preparePatchpointForExceptions(patchpoint); @@ -8021,6 +8039,7 @@ IGNORE_CLANG_WARNINGS_END patchpoint->append(m_notCellMask, ValueRep::lateReg(GPRInfo::notCellMaskRegister)); patchpoint->append(m_numberTag, ValueRep::lateReg(GPRInfo::numberTagRegister)); patchpoint->clobber(RegisterSet::macroClobberedGPRs()); + patchpoint->clobber(RegisterSet::macroClobberedFPRs()); patchpoint->numGPScratchRegisters = Options::useHandlerICInFTL() ? 1 : 0; RefPtr exceptionHandle = @@ -13934,6 +13953,7 @@ IGNORE_CLANG_WARNINGS_END patchpoint->append(m_notCellMask, ValueRep::reg(GPRInfo::notCellMaskRegister)); patchpoint->append(m_numberTag, ValueRep::reg(GPRInfo::numberTagRegister)); patchpoint->clobber(RegisterSet::macroClobberedGPRs()); + patchpoint->clobber(RegisterSet::macroClobberedFPRs()); patchpoint->clobberLate(RegisterSet::registersToSaveForJSCall(RegisterSet::allScalarRegisters())); patchpoint->resultConstraints = { ValueRep::reg(GPRInfo::returnValueGPR) }; @@ -14025,6 +14045,7 @@ IGNORE_CLANG_WARNINGS_END } patchpoint->clobber(RegisterSet::macroClobberedGPRs()); + patchpoint->clobber(RegisterSet::macroClobberedFPRs()); if (!isTail) { patchpoint->clobberLate(RegisterSet::registersToSaveForJSCall(RegisterSet::allScalarRegisters())); patchpoint->resultConstraints = { ValueRep::reg(GPRInfo::returnValueGPR) }; @@ -14443,6 +14464,7 @@ IGNORE_CLANG_WARNINGS_END RefPtr exceptionHandle = preparePatchpointForExceptions(patchpoint); patchpoint->clobber(RegisterSet::macroClobberedGPRs()); + patchpoint->clobber(RegisterSet::macroClobberedFPRs()); patchpoint->clobber(RegisterSet::registersToSaveForJSCall(RegisterSet::allScalarRegisters())); // No inputs will be in a volatile register. patchpoint->resultConstraints = { ValueRep::reg(GPRInfo::returnValueGPR) }; @@ -14704,6 +14726,7 @@ IGNORE_CLANG_WARNINGS_END patchpoint->append(m_numberTag, ValueRep::reg(GPRInfo::numberTagRegister)); patchpoint->clobber(RegisterSet::macroClobberedGPRs()); + patchpoint->clobber(RegisterSet::macroClobberedFPRs()); patchpoint->clobberLate(RegisterSet::registersToSaveForJSCall(RegisterSet::allScalarRegisters())); patchpoint->resultConstraints = { ValueRep::reg(GPRInfo::returnValueGPR) }; @@ -14941,6 +14964,7 @@ IGNORE_CLANG_WARNINGS_END patchpoint->append(m_notCellMask, ValueRep::reg(GPRInfo::notCellMaskRegister)); patchpoint->append(m_numberTag, ValueRep::reg(GPRInfo::numberTagRegister)); patchpoint->clobber(RegisterSet::macroClobberedGPRs()); + patchpoint->clobber(RegisterSet::macroClobberedFPRs()); patchpoint->clobberLate(RegisterSet::registersToSaveForJSCall(RegisterSet::allScalarRegisters())); patchpoint->resultConstraints = { ValueRep::reg(GPRInfo::returnValueGPR) }; @@ -15030,6 +15054,7 @@ IGNORE_CLANG_WARNINGS_END PatchpointValue* patchpoint = m_out.patchpoint(Int64); patchpoint->append(ConstrainedValue(argument, ValueRep::SomeLateRegister)); patchpoint->clobber(RegisterSet::macroClobberedGPRs()); + patchpoint->clobber(RegisterSet::macroClobberedFPRs()); patchpoint->setGenerator( [=](CCallHelpers& jit, const StackmapGenerationParams& params) { AllowMacroScratchRegisterUsage allowScratch(jit); @@ -17702,6 +17727,7 @@ IGNORE_CLANG_WARNINGS_END patchpoint->append(m_notCellMask, ValueRep::lateReg(GPRInfo::notCellMaskRegister)); patchpoint->append(m_numberTag, ValueRep::lateReg(GPRInfo::numberTagRegister)); patchpoint->clobber(RegisterSet::macroClobberedGPRs()); + patchpoint->clobber(RegisterSet::macroClobberedFPRs()); if constexpr (type == AccessType::InById) patchpoint->numGPScratchRegisters = Options::useHandlerICInFTL() ? 2 : 0; else @@ -17862,6 +17888,7 @@ IGNORE_CLANG_WARNINGS_END patchpoint->append(m_notCellMask, ValueRep::lateReg(GPRInfo::notCellMaskRegister)); patchpoint->append(m_numberTag, ValueRep::lateReg(GPRInfo::numberTagRegister)); patchpoint->clobber(RegisterSet::macroClobberedGPRs()); + patchpoint->clobber(RegisterSet::macroClobberedFPRs()); patchpoint->numGPScratchRegisters = 3; RefPtr exceptionHandle = preparePatchpointForExceptions(patchpoint); @@ -17937,6 +17964,7 @@ IGNORE_CLANG_WARNINGS_END patchpoint->append(m_notCellMask, ValueRep::lateReg(GPRInfo::notCellMaskRegister)); patchpoint->append(m_numberTag, ValueRep::lateReg(GPRInfo::numberTagRegister)); patchpoint->clobber(RegisterSet::macroClobberedGPRs()); + patchpoint->clobber(RegisterSet::macroClobberedFPRs()); patchpoint->numGPScratchRegisters = 4; RefPtr exceptionHandle = preparePatchpointForExceptions(patchpoint); @@ -18301,6 +18329,7 @@ IGNORE_CLANG_WARNINGS_END patchpoint->numGPScratchRegisters = Options::useHandlerICInFTL() ? 1 : 0; patchpoint->resultConstraints = { ValueRep::SomeEarlyRegister }; patchpoint->clobber(RegisterSet::macroClobberedGPRs()); + patchpoint->clobber(RegisterSet::macroClobberedFPRs()); RefPtr exceptionHandle = preparePatchpointForExceptions(patchpoint); @@ -19206,6 +19235,7 @@ IGNORE_CLANG_WARNINGS_END patchpoint->append(m_notCellMask, ValueRep::lateReg(GPRInfo::notCellMaskRegister)); patchpoint->append(m_numberTag, ValueRep::lateReg(GPRInfo::numberTagRegister)); patchpoint->clobber(RegisterSet::macroClobberedGPRs()); + patchpoint->clobber(RegisterSet::macroClobberedFPRs()); patchpoint->numGPScratchRegisters = Options::useHandlerICInFTL() ? 1 : 0; RefPtr exceptionHandle = preparePatchpointForExceptions(patchpoint); @@ -20251,6 +20281,7 @@ IGNORE_CLANG_WARNINGS_END patchpoint->append(ConstrainedValue(argument, ValueRep::SomeLateRegister)); patchpoint->numGPScratchRegisters = inlineCodeStats8Bit.needsTemp2() ? 6 : 5; patchpoint->clobber(RegisterSet::macroClobberedGPRs()); + patchpoint->clobber(RegisterSet::macroClobberedFPRs()); patchpoint->setGenerator( [=] (CCallHelpers& jit, const StackmapGenerationParams& params) { AllowMacroScratchRegisterUsage allowScratch(jit); @@ -21083,6 +21114,7 @@ IGNORE_CLANG_WARNINGS_END // https://bugs.webkit.org/show_bug.cgi?id=152848 patchpoint->clobber(RegisterSet::macroClobberedGPRs()); + patchpoint->clobber(RegisterSet::macroClobberedFPRs()); RefPtr exceptionHandle = preparePatchpointForExceptions(patchpoint); @@ -21172,6 +21204,7 @@ IGNORE_CLANG_WARNINGS_END patchpoint->append(m_notCellMask, ValueRep::lateReg(GPRInfo::notCellMaskRegister)); patchpoint->append(m_numberTag, ValueRep::lateReg(GPRInfo::numberTagRegister)); patchpoint->clobber(RegisterSet::macroClobberedGPRs()); + patchpoint->clobber(RegisterSet::macroClobberedFPRs()); patchpoint->numGPScratchRegisters = Options::useHandlerICInFTL() ? 2 : 0; RefPtr exceptionHandle = @@ -21914,6 +21947,7 @@ IGNORE_CLANG_WARNINGS_END patchpoint->numGPScratchRegisters = domJIT->numGPScratchRegisters; patchpoint->numFPScratchRegisters = domJIT->numFPScratchRegisters; patchpoint->clobber(RegisterSet::macroClobberedGPRs()); + patchpoint->clobber(RegisterSet::macroClobberedFPRs()); State* state = &m_ftlState; Node* node = m_node; @@ -22115,6 +22149,7 @@ IGNORE_CLANG_WARNINGS_END patchpoint->append(m_numberTag, ValueRep::reg(GPRInfo::numberTagRegister)); RefPtr exceptionHandle = preparePatchpointForExceptions(patchpoint); patchpoint->clobber(RegisterSet::macroClobberedGPRs()); + patchpoint->clobber(RegisterSet::macroClobberedFPRs()); patchpoint->numGPScratchRegisters = domJIT->numGPScratchRegisters; patchpoint->numFPScratchRegisters = domJIT->numFPScratchRegisters; patchpoint->resultConstraints = { ValueRep::SomeEarlyRegister }; @@ -23555,6 +23590,7 @@ IGNORE_CLANG_WARNINGS_END preparePatchpointForExceptions(patchpoint); patchpoint->numGPScratchRegisters = BinaryBitOpGenerator::needsScratchGPR ? 1 : 0; patchpoint->clobber(RegisterSet::macroClobberedGPRs()); + patchpoint->clobber(RegisterSet::macroClobberedFPRs()); patchpoint->resultConstraints = { ValueRep::SomeEarlyRegister }; State* state = &m_ftlState; CodeOrigin semanticNodeOrigin = node->origin.semantic; @@ -23621,6 +23657,7 @@ IGNORE_CLANG_WARNINGS_END patchpoint->numGPScratchRegisters = 1; patchpoint->numFPScratchRegisters = 1; patchpoint->clobber(RegisterSet::macroClobberedGPRs()); + patchpoint->clobber(RegisterSet::macroClobberedFPRs()); patchpoint->resultConstraints = { ValueRep::SomeEarlyRegister }; State* state = &m_ftlState; CodeOrigin semanticNodeOrigin = node->origin.semantic; @@ -23697,6 +23734,7 @@ IGNORE_CLANG_WARNINGS_END if (isARM64()) { // emitAllocateWithNonNullAllocator uses the scratch registers on ARM. patchpoint->clobber(RegisterSet::macroClobberedGPRs()); + patchpoint->clobber(RegisterSet::macroClobberedFPRs()); } patchpoint->effects.terminal = true; if (actualAllocator.isConstant())