diff --git a/js/src/jit/CacheIRCompiler.cpp b/js/src/jit/CacheIRCompiler.cpp index 2bcdd84d54d3..e4d710733f9b 100644 --- a/js/src/jit/CacheIRCompiler.cpp +++ b/js/src/jit/CacheIRCompiler.cpp @@ -53,6 +53,7 @@ #include "jit/SharedICHelpers-inl.h" #include "jit/VMFunctionList-inl.h" + using namespace js; using namespace js::jit; @@ -6600,6 +6601,11 @@ bool CacheIRCompiler::emitComparePointerResultShared(JSOp op, TypedOperandId lhsId, TypedOperandId rhsId) { JitSpew(JitSpew_Codegen, "%s", __FUNCTION__); +#ifdef JS_CACHET + if (isCachetEnabled_) { + cachet::Impl_CacheIR::Op_ComparePointerResult(cachet::CachetContext {this, cx_}, masm, op, lhsId, rhsId); + } else { +#endif AutoOutputRegister output(*this); Register left = allocator.useRegister(masm, lhsId); @@ -6617,6 +6623,9 @@ bool CacheIRCompiler::emitComparePointerResultShared(JSOp op, masm.bind(&ifTrue); EmitStoreBoolean(masm, true, output); masm.bind(&done); +#ifdef JS_CACHET + } +#endif return true; } @@ -6662,6 +6671,11 @@ bool CacheIRCompiler::emitCompareInt32Result(JSOp op, Int32OperandId lhsId, bool CacheIRCompiler::emitCompareDoubleResult(JSOp op, NumberOperandId lhsId, NumberOperandId rhsId) { JitSpew(JitSpew_Codegen, "%s", __FUNCTION__); +#ifdef JS_CACHET + if (isCachetEnabled_) { + cachet::Impl_CacheIR::Op_CompareDoubleResult(cachet::CachetContext {this, cx_}, masm, op, lhsId, rhsId); + } else { +#endif AutoOutputRegister output(*this); // Float register must be preserved. The Compare ICs use the fact that @@ -6686,6 +6700,9 @@ bool CacheIRCompiler::emitCompareDoubleResult(JSOp op, NumberOperandId lhsId, masm.bind(&ifTrue); EmitStoreBoolean(masm, true, output); masm.bind(&done); +#ifdef JS_CACHET + } +#endif return true; } diff --git a/js/src/jit/CachetCompiler.cpp b/js/src/jit/CachetCompiler.cpp index 22d4512e98c6..00ef4a427fc4 100644 --- a/js/src/jit/CachetCompiler.cpp +++ b/js/src/jit/CachetCompiler.cpp @@ -1365,6 +1365,15 @@ void EmitOp_BranchTest32Imm(Cachet_ContextRef cx, ops.branchTest32(param_condition, param_lhsReg, Imm32(param_rhsInt32), param_branch); } +void EmitOp_BranchDouble(Cachet_ContextRef cx, + IR_MASM::OpsRef ops, + Type_DoubleCondition::Ref param_condition, + Type_FloatReg::Ref param_lhsReg, + Type_FloatReg::Ref param_rhsReg, + IR_MASM::LabelRef param_branch) { + ops.branchDouble(param_condition, param_lhsReg, param_rhsReg, param_branch); +} + void EmitOp_BranchAdd32(Cachet_ContextRef cx, IR_MASM::OpsRef ops, Type_Condition::Ref param_condition, @@ -1608,6 +1617,11 @@ Type_ValueReg::Val Fn_useValueId(Cachet_ContextRef cx, IR_MASM::OpsRef ops, return detail::CompilerInternals::allocator(cx).useValueRegister(ops, param_valueId); } +Type_Reg::Val Fn_useTypedId(Cachet_ContextRef cx, IR_MASM::OpsRef ops, + Type_TypedId::Ref param_typedId) { + return detail::CompilerInternals::allocator(cx).useRegister(ops, param_typedId); +} + Type_Reg::Val Fn_useObjectId(Cachet_ContextRef cx, IR_MASM::OpsRef ops, Type_ObjectId::Ref param_objectId) { return detail::CompilerInternals::allocator(cx).useRegister(ops, param_objectId); @@ -1707,6 +1721,10 @@ Type_Bool::Val Fn_objectGuardNeedsSpectreMitigations( return detail::CompilerInternals::objectGuardNeedsSpectreMitigations(cx, param_objectId); } +void Fn_ensureDoubleRegister(Cachet_ContextRef cx, IR_MASM::OpsRef ops, Type_NumberId::Ref op, Type_FloatReg::Ref dest) { + detail::CompilerInternals::allocator(cx).ensureDoubleRegister(detail::CompilerInternals::masm(cx), op, dest); +} + }; // namespace Impl_CacheIR Type_Bool::Val Fn_isCacheableProtoChain(Cachet_ContextRef cx, diff --git a/js/src/jit/CachetCompiler.h b/js/src/jit/CachetCompiler.h index f2e5157ca682..36c70b5bc582 100644 --- a/js/src/jit/CachetCompiler.h +++ b/js/src/jit/CachetCompiler.h @@ -254,6 +254,7 @@ using Type_GeneralRegSet = PrimitiveType; using Type_FloatRegSet = PrimitiveType; using Type_LiveRegSet = PrimitiveType; using Type_Condition = PrimitiveType; +using Type_DoubleCondition = PrimitiveType; using Type_Address = StructType; using Type_Scale = PrimitiveType; using Type_BaseIndex = StructType; @@ -674,6 +675,10 @@ inline Type_PhyFloatReg::Ref Variant_Xmm0(Cachet_ContextRef cx) { return X86Encoding::xmm0; } +inline Type_PhyFloatReg::Ref Variant_Xmm1(Cachet_ContextRef cx) { + return X86Encoding::xmm1; +} + inline Type_PhyFloatReg::Ref Variant_Xmm15(Cachet_ContextRef cx) { return X86Encoding::xmm15; } @@ -760,6 +765,66 @@ inline Type_Condition::Ref Variant_BelowOrEqual(Cachet_ContextRef cx) { }; // namespace Impl_Condition +namespace Impl_DoubleCondition { + +inline Type_DoubleCondition::Ref Variant_Ordered(Cachet_ContextRef cx) { + return Assembler::DoubleCondition::DoubleOrdered; +} + +inline Type_DoubleCondition::Ref Variant_Equal(Cachet_ContextRef cx) { + return Assembler::DoubleCondition::DoubleEqual; +} + +inline Type_DoubleCondition::Ref Variant_NotEqual(Cachet_ContextRef cx) { + return Assembler::DoubleCondition::DoubleNotEqual; +} + +inline Type_DoubleCondition::Ref Variant_GreaterThan(Cachet_ContextRef cx) { + return Assembler::DoubleCondition::DoubleGreaterThan; +} + +inline Type_DoubleCondition::Ref Variant_GreaterThanOrEqual(Cachet_ContextRef cx) { + return Assembler::DoubleCondition::DoubleGreaterThanOrEqual; +} + +inline Type_DoubleCondition::Ref Variant_LessThan(Cachet_ContextRef cx) { + return Assembler::DoubleCondition::DoubleLessThan; +} + +inline Type_DoubleCondition::Ref Variant_LessThanOrEqual(Cachet_ContextRef cx) { + return Assembler::DoubleCondition::DoubleLessThanOrEqual; +} + +inline Type_DoubleCondition::Ref Variant_Unordered(Cachet_ContextRef cx) { + return Assembler::DoubleCondition::DoubleUnordered; +} + +inline Type_DoubleCondition::Ref Variant_EqualOrUnordered(Cachet_ContextRef cx) { + return Assembler::DoubleCondition::DoubleEqualOrUnordered; +} + +inline Type_DoubleCondition::Ref Variant_NotEqualOrUnordered(Cachet_ContextRef cx) { + return Assembler::DoubleCondition::DoubleNotEqualOrUnordered; +} + +inline Type_DoubleCondition::Ref Variant_GreaterThanOrUnordered(Cachet_ContextRef cx) { + return Assembler::DoubleCondition::DoubleGreaterThanOrUnordered; +} + +inline Type_DoubleCondition::Ref Variant_GreaterThanOrEqualOrUnordered(Cachet_ContextRef cx) { + return Assembler::DoubleCondition::DoubleGreaterThanOrEqualOrUnordered; +} + +inline Type_DoubleCondition::Ref Variant_LessThanOrUnordered(Cachet_ContextRef cx) { + return Assembler::DoubleCondition::DoubleLessThanOrUnordered; +} + +inline Type_DoubleCondition::Ref Variant_LessThanOrEqualOrUnordered(Cachet_ContextRef cx) { + return Assembler::DoubleCondition::DoubleLessThanOrEqualOrUnordered; +} + +}; // namespace Impl_DoubleCondition + namespace Impl_Scale { inline Type_Scale::Ref Variant_TimesOne(Cachet_ContextRef cx) { diff --git a/js/src/jit/GenerateCachetFiles.py b/js/src/jit/GenerateCachetFiles.py index 921612adf6bb..3e1b0964ebfe 100755 --- a/js/src/jit/GenerateCachetFiles.py +++ b/js/src/jit/GenerateCachetFiles.py @@ -24,7 +24,7 @@ def generate_cachet_impl(c_out, cachet_src): script_file_path = os.path.abspath(__file__) jit_dir_path = os.path.dirname(script_file_path) cachet_compiler_exe_path = os.path.abspath(os.path.join(jit_dir_path, - "..", "..", "..", "..", "cachet", "target", "debug", "cachet-compiler")) + "..", "..", "..", "..", "cachet", "target", "release", "cachet-compiler")) p = subprocess.Popen([cachet_compiler_exe_path, cachet_src, "--cpp-decls", h_tmp, "--cpp-defs", inc_tmp], stdout=subprocess.PIPE, stderr=subprocess.PIPE) diff --git a/js/src/jit/cachet/CacheIR.cachet b/js/src/jit/cachet/CacheIR.cachet index 3e7bdffa7d6a..bc5f6a7b0b86 100644 --- a/js/src/jit/cachet/CacheIR.cachet +++ b/js/src/jit/cachet/CacheIR.cachet @@ -1239,6 +1239,22 @@ ir CacheIR emits MASM { bind done; } + op ComparePointerResult(jsop: JSOp, lhsId: TypedId, rhsId: TypedId) { + let lhsReg = CacheIR::useTypedId(lhsId); + let rhsReg = CacheIR::useTypedId(rhsId); + + label ifTrue: MASM; + label done: MASM; + + emit MASM::Branch32(Condition::fromJSOp(jsop, true), lhsReg, rhsReg, ifTrue); + CacheIR::emitStoreBool(false, CacheIR::outputReg); + emit MASM::Jump(done); + + bind ifTrue; + CacheIR::emitStoreBool(true, CacheIR::outputReg); + bind done; + } + op CompareNullUndefinedResult(jsop: JSOp, isUndefined: Bool, inputId: ValueId) { let inputReg = CacheIR::useValueId(inputId); let scratchReg = CacheIR::allocateReg(); @@ -1318,6 +1334,31 @@ ir CacheIR emits MASM { } + op CompareDoubleResult(jsop: JSOp, lhsId: NumberId, rhsId: NumberId) { + // TODO(jlwoodwa): elided AutoAvailableFloatRegister; check that this is safe + let floatScratch0 = FloatReg::floatReg0(); + let floatScratch1 = FloatReg::floatReg1(); + + // let failure = CacheIR::addFailurePath(); + // TODO(jlwoodwa): is this as pointless as it looks? + + CacheIR::ensureDoubleRegister(lhsId, floatScratch0); + CacheIR::ensureDoubleRegister(rhsId, floatScratch1); + + label ifTrue: MASM; + label done: MASM; + + emit MASM::BranchDouble(DoubleCondition::fromJSOp(jsop), floatScratch0, floatScratch1, ifTrue); + CacheIR::emitStoreBool(false, CacheIR::outputReg); + emit MASM::Jump(done); + + bind ifTrue; + CacheIR::emitStoreBool(true, CacheIR::outputReg); + bind done; + + // CacheIR::releaseFailurePath(); + } + op Int32AddResult(lhsId: Int32Id, rhsId: Int32Id) { let lhsReg = CacheIR::useInt32Id(lhsId); let rhsReg = CacheIR::useInt32Id(rhsId); diff --git a/js/src/jit/cachet/MacroAssembler.cachet b/js/src/jit/cachet/MacroAssembler.cachet index 76480c20b045..6ac7e975de6b 100644 --- a/js/src/jit/cachet/MacroAssembler.cachet +++ b/js/src/jit/cachet/MacroAssembler.cachet @@ -118,6 +118,10 @@ impl FloatReg { FloatReg::newDouble(PhyFloatReg::Xmm0) } + fn floatReg1() -> FloatReg { + FloatReg::newDouble(PhyFloatReg::Xmm1) + } + fn doubleScratchReg() -> FloatReg { FloatReg::newDouble(PhyFloatReg::Xmm15) } @@ -623,6 +627,43 @@ impl Condition { } } +enum DoubleCondition { + Ordered, + Equal, + NotEqual, + GreaterThan, + GreaterThanOrEqual, + LessThan, + LessThanOrEqual, + Unordered, + EqualOrUnordered, + NotEqualOrUnordered, + GreaterThanOrUnordered, + GreaterThanOrEqualOrUnordered, + LessThanOrUnordered, + LessThanOrEqualOrUnordered, +} + +impl DoubleCondition { + fn fromJSOp(jsop: JSOp) -> DoubleCondition { + if jsop == JSOp::Eq || jsop == JSOp::StrictEq { + return DoubleCondition::Equal; + } else if jsop == JSOp::Ne || jsop == JSOp::StrictNe { + return DoubleCondition::NotEqualOrUnordered; + } else if jsop == JSOp::Lt { + return DoubleCondition::LessThan; + } else if jsop == JSOp::Le { + return DoubleCondition::LessThanOrEqual; + } else if jsop == JSOp::Gt { + return DoubleCondition::GreaterThan; + } else if jsop == JSOp::Ge { + return DoubleCondition::GreaterThanOrEqual; + } + assert false; + return DoubleCondition::Ordered; // TODO(jlwoodwa): this workaround should not be necessary + } +} + struct Address { base: Reg, offset: Int32, @@ -1750,6 +1791,71 @@ ir MASM { } } + op BranchDouble(condition: DoubleCondition, lhs: FloatReg, rhs: FloatReg, label branch: MASM) { + let lhsDouble = MASM::getDouble(lhs); + let rhsDouble = MASM::getDouble(rhs); + + if condition == DoubleCondition::Ordered { + if Float64::ordered(lhsDouble, rhsDouble) { + goto branch; + } + } else if condition == DoubleCondition::Equal { + if Float64::equal(lhsDouble, rhsDouble) { + goto branch; + } + } else if condition == DoubleCondition::NotEqual { + if Float64::notEqual(lhsDouble, rhsDouble) { + goto branch; + } + } else if condition == DoubleCondition::GreaterThan { + if Float64::greaterThan(lhsDouble, rhsDouble) { + goto branch; + } + } else if condition == DoubleCondition::GreaterThanOrEqual { + if Float64::greaterThanOrEqual(lhsDouble, rhsDouble) { + goto branch; + } + } else if condition == DoubleCondition::LessThan { + if Float64::lessThan(lhsDouble, rhsDouble) { + goto branch; + } + } else if condition == DoubleCondition::LessThanOrEqual { + if Float64::lessThanOrEqual(lhsDouble, rhsDouble) { + goto branch; + } + } else if condition == DoubleCondition::Unordered { + if Float64::unordered(lhsDouble, rhsDouble) { + goto branch; + } + } else if condition == DoubleCondition::EqualOrUnordered { + if Float64::equalOrUnordered(lhsDouble, rhsDouble) { + goto branch; + } + } else if condition == DoubleCondition::NotEqualOrUnordered { + if Float64::notEqualOrUnordered(lhsDouble, rhsDouble) { + goto branch; + } + } else if condition == DoubleCondition::GreaterThanOrUnordered { + if Float64::greaterThanOrUnordered(lhsDouble, rhsDouble) { + goto branch; + } + } else if condition == DoubleCondition::GreaterThanOrEqualOrUnordered { + if Float64::greaterThanOrEqualOrUnordered(lhsDouble, rhsDouble) { + goto branch; + } + } else if condition == DoubleCondition::LessThanOrUnordered { + if Float64::lessThanOrUnordered(lhsDouble, rhsDouble) { + goto branch; + } + } else if condition == DoubleCondition::LessThanOrEqualOrUnordered { + if Float64::lessThanOrEqualOrUnordered(lhsDouble, rhsDouble) { + goto branch; + } + } else { + assert false; + } + } + op BranchAdd32(condition: Condition, srcReg: Reg, dstReg: Reg, label branch: MASM) { let lhsInt32 = MASM::getInt32(srcReg); let rhsInt32 = MASM::getInt32(dstReg); diff --git a/js/src/jit/cachet/VM.cachet b/js/src/jit/cachet/VM.cachet index cf8d22a63ca5..f7c64ae37df2 100644 --- a/js/src/jit/cachet/VM.cachet +++ b/js/src/jit/cachet/VM.cachet @@ -327,6 +327,21 @@ impl Float64 { } unsafe fn fromUInt32Unchecked(uint32: UInt32) -> Float64; + + fn ordered(lhs: Float64, rhs: Float64) -> Bool; + fn equal(lhs: Float64, rhs: Float64) -> Bool; + fn notEqual(lhs: Float64, rhs: Float64) -> Bool; + fn greaterThan(lhs: Float64, rhs: Float64) -> Bool; + fn greaterThanOrEqual(lhs: Float64, rhs: Float64) -> Bool; + fn lessThan(lhs: Float64, rhs: Float64) -> Bool; + fn lessThanOrEqual(lhs: Float64, rhs: Float64) -> Bool; + fn unordered(lhs: Float64, rhs: Float64) -> Bool; + fn equalOrUnordered(lhs: Float64, rhs: Float64) -> Bool; + fn notEqualOrUnordered(lhs: Float64, rhs: Float64) -> Bool; + fn greaterThanOrUnordered(lhs: Float64, rhs: Float64) -> Bool; + fn greaterThanOrEqualOrUnordered(lhs: Float64, rhs: Float64) -> Bool; + fn lessThanOrUnordered(lhs: Float64, rhs: Float64) -> Bool; + fn lessThanOrEqualOrUnordered(lhs: Float64, rhs: Float64) -> Bool; } struct Simd128;