Skip to content

Commit

Permalink
oopjit branch folding for BrEq,Neq with numbers, bools, null, undefined
Browse files Browse the repository at this point in the history
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
  • Loading branch information
sigatrev committed Sep 17, 2018
1 parent be2b997 commit 3677f7c
Showing 1 changed file with 107 additions and 18 deletions.
125 changes: 107 additions & 18 deletions lib/Backend/GlobOpt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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())
Expand All @@ -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<Js::Var>(func->GetScriptContextInfo()->GetTrueAddr()) ||
src1Var == reinterpret_cast<Js::Var>(func->GetScriptContextInfo()->GetFalseAddr()) ||
src1Var == reinterpret_cast<Js::Var>(func->GetScriptContextInfo()->GetNullAddr()) ||
src1Var == reinterpret_cast<Js::Var>(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)
Expand Down Expand Up @@ -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:
Expand All @@ -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:
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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;

Expand Down

0 comments on commit 3677f7c

Please sign in to comment.