From 3677f7ce9a4947ff7f4e5cda13a9287c3048fe58 Mon Sep 17 00:00:00 2001 From: Matt Gardner Date: Mon, 17 Sep 2018 12:13:34 -0700 Subject: [PATCH] oopjit branch folding for BrEq,Neq with numbers, bools, null, undefined this commit handles branch folding checks for when operands are floats, booleans, null, or undefined. TryOptConstFoldBrEqual is already handling ints in a more robust way --- lib/Backend/GlobOpt.cpp | 125 ++++++++++++++++++++++++++++++++++------ 1 file changed, 107 insertions(+), 18 deletions(-) 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;