diff --git a/lib/Backend/GlobOpt.cpp b/lib/Backend/GlobOpt.cpp index a248cbfa58d..e4fde067be2 100644 --- a/lib/Backend/GlobOpt.cpp +++ b/lib/Backend/GlobOpt.cpp @@ -6468,6 +6468,12 @@ GlobOpt::GetConstantVar(IR::Opnd *opnd, Value *val) return Js::TaggedInt::ToVarUnchecked(opnd->AsIntConstOpnd()->AsInt32()); } } +#if FLOATVAR + else if (opnd->IsFloatConstOpnd()) + { + return Js::JavascriptNumber::ToVar(opnd->AsFloatConstOpnd()->m_value); + } +#endif else if (opnd->IsRegOpnd() && opnd->AsRegOpnd()->m_sym->IsSingleDef()) { if (valueInfo->IsBoolean()) @@ -6489,19 +6495,110 @@ GlobOpt::GetConstantVar(IR::Opnd *opnd, Value *val) { return (Js::Var)this->func->GetScriptContextInfo()->GetNullAddr(); } +#if FLOATVAR + else if (valueInfo->IsFloat()) + { + IR::Instr * defInstr = opnd->AsRegOpnd()->m_sym->GetInstrDef(); + if (defInstr->m_opcode == Js::OpCode::LdC_F8_R8 && defInstr->GetSrc1()->IsFloatConstOpnd()) + { + return Js::JavascriptNumber::ToVar(defInstr->GetSrc1()->AsFloatConstOpnd()->m_value); + } + } +#endif } return nullptr; } -bool BoolAndIntStaticAndTypeMismatch(Value* src1Val, Value* src2Val, Js::Var src1Var, Js::Var src2Var) +namespace { - ValueInfo *src1ValInfo = src1Val->GetValueInfo(); - ValueInfo *src2ValInfo = src2Val->GetValueInfo(); - return (src1ValInfo->IsNumber() && src1Var && src2ValInfo->IsBoolean() && src1Var != Js::TaggedInt::ToVarUnchecked(0) && src1Var != Js::TaggedInt::ToVarUnchecked(1)) || - (src2ValInfo->IsNumber() && src2Var && src1ValInfo->IsBoolean() && src2Var != Js::TaggedInt::ToVarUnchecked(0) && src2Var != Js::TaggedInt::ToVarUnchecked(1)); -} + bool TryCompIntAndFloat(bool * result, Js::Var left, Js::Var right) + { + if (Js::TaggedInt::Is(left)) + { + // If both are tagged ints we should not get here. + Assert(!Js::TaggedInt::Is(right)); + if (Js::JavascriptNumber::Is_NoTaggedIntCheck(right)) + { + double value = Js::JavascriptNumber::GetValue(right); + *result = (Js::TaggedInt::ToInt32(left) == value); + return true; + } + } + return false; + } + + bool Op_JitEq(bool * result, Value * src1Val, Value * src2Val, Js::Var src1Var, Js::Var src2Var, Func * func, bool isStrict) + { + Assert(src1Val != nullptr && src2Val != nullptr); + Assert(src1Var != nullptr && src2Var != nullptr); + + if (src1Var == src2Var) + { + if (Js::TaggedInt::Is(src1Var)) + { + *result = true; + return true; + } + + if (!isStrict && src1Val->GetValueInfo()->IsNotFloat()) + { + // If the vars are equal and they are not NaN, non-strict equal returns true. Not float guarantees not NaN. + *result = true; + return true; + } + +#if FLOATVAR + if (Js::JavascriptNumber::Is_NoTaggedIntCheck(src1Var)) + { + *result = !Js::JavascriptNumber::IsNan(Js::JavascriptNumber::GetValue(src1Var)); + return true; + } +#endif + + if (src1Var == reinterpret_cast(func->GetScriptContextInfo()->GetTrueAddr()) || + src1Var == reinterpret_cast(func->GetScriptContextInfo()->GetFalseAddr()) || + src1Var == reinterpret_cast(func->GetScriptContextInfo()->GetNullAddr()) || + src1Var == reinterpret_cast(func->GetScriptContextInfo()->GetUndefinedAddr())) + { + *result = true; + return true; + } + + // Other var comparisons require the runtime to prove. + return false; + } + +#if FLOATVAR + if (TryCompIntAndFloat(result, src1Var, src2Var) || TryCompIntAndFloat(result, src2Var, src1Var)) + { + return true; + } + +#endif + return false; + } + + bool Op_JitNeq(bool * result, Value * src1Val, Value * src2Val, Js::Var src1Var, Js::Var src2Var, Func * func, bool isStrict) + { + if (Op_JitEq(result, src1Val, src2Val, src1Var, src2Var, func, isStrict)) + { + *result = !*result; + return true; + } + + return false; + } + + bool BoolAndIntStaticAndTypeMismatch(Value* src1Val, Value* src2Val, Js::Var src1Var, Js::Var src2Var) + { + ValueInfo *src1ValInfo = src1Val->GetValueInfo(); + ValueInfo *src2ValInfo = src2Val->GetValueInfo(); + return (src1ValInfo->IsNumber() && src1Var && src2ValInfo->IsBoolean() && src1Var != Js::TaggedInt::ToVarUnchecked(0) && src1Var != Js::TaggedInt::ToVarUnchecked(1)) || + (src2ValInfo->IsNumber() && src2Var && src1ValInfo->IsBoolean() && src2Var != Js::TaggedInt::ToVarUnchecked(0) && src2Var != Js::TaggedInt::ToVarUnchecked(1)); + } +} bool GlobOpt::CanProveConditionalBranch(IR::Instr *instr, Value *src1Val, Value *src2Val, Js::Var src1Var, Js::Var src2Var, bool *result) @@ -6629,12 +6726,10 @@ GlobOpt::CanProveConditionalBranch(IR::Instr *instr, Value *src1Val, Value *src2 } else { - if (func->IsOOPJIT() || !CONFIG_FLAG(OOPJITMissingOpts)) + if (!Op_JitEq(result, src1Val, src2Val, src1Var, src2Var, this->func, false /* isStrict */)) { - // TODO: OOP JIT, const folding return false; } - *result = Js::JavascriptOperators::Equal(src1Var, src2Var, this->func->GetScriptContext()); } break; case Js::OpCode::BrNeq_A: @@ -6661,12 +6756,10 @@ GlobOpt::CanProveConditionalBranch(IR::Instr *instr, Value *src1Val, Value *src2 } else { - if (func->IsOOPJIT() || !CONFIG_FLAG(OOPJITMissingOpts)) + if (!Op_JitNeq(result, src1Val, src2Val, src1Var, src2Var, this->func, false /* isStrict */)) { - // TODO: OOP JIT, const folding return false; } - *result = Js::JavascriptOperators::NotEqual(src1Var, src2Var, this->func->GetScriptContext()); } break; case Js::OpCode::BrSrEq_A: @@ -6702,12 +6795,10 @@ GlobOpt::CanProveConditionalBranch(IR::Instr *instr, Value *src1Val, Value *src2 } else { - if (func->IsOOPJIT() || !CONFIG_FLAG(OOPJITMissingOpts)) + if (!Op_JitEq(result, src1Val, src2Val, src1Var, src2Var, this->func, true /* isStrict */)) { - // TODO: OOP JIT, const folding return false; } - *result = Js::JavascriptOperators::StrictEqual(src1Var, src2Var, this->func->GetScriptContext()); } break; @@ -6744,12 +6835,10 @@ GlobOpt::CanProveConditionalBranch(IR::Instr *instr, Value *src1Val, Value *src2 } else { - if (func->IsOOPJIT() || !CONFIG_FLAG(OOPJITMissingOpts)) + if (!Op_JitNeq(result, src1Val, src2Val, src1Var, src2Var, this->func, true /* isStrict */)) { - // TODO: OOP JIT, const folding return false; } - *result = Js::JavascriptOperators::NotStrictEqual(src1Var, src2Var, this->func->GetScriptContext()); } break;