@@ -2007,6 +2007,13 @@ Lowerer::LowerRange(IR::Instr *instrStart, IR::Instr *instrEnd, bool defaultDoFa
20072007 this->LowerBrCMem(instr, IR::HelperOp_Equal, false);
20082008 }
20092009 }
2010+ else if (this->GenerateFastBrEqBoolInt(instr->AsBranchInstr(), &needHelper))
2011+ {
2012+ if (needHelper)
2013+ {
2014+ this->LowerBrCMem(instr, IR::HelperOp_Equal, false);
2015+ }
2016+ }
20102017 else
20112018 {
20122019 if (needHelper)
@@ -2117,6 +2124,17 @@ Lowerer::LowerRange(IR::Instr *instrStart, IR::Instr *instrEnd, bool defaultDoFa
21172124 {
21182125 this->LowerBrCMem(instr, IR::HelperOp_NotEqual, false);
21192126 }
2127+ else if (this->GenerateFastBrEqBoolInt(instr->AsBranchInstr(), &needHelper))
2128+ {
2129+ if (needHelper)
2130+ {
2131+ this->LowerBrCMem(instr, IR::HelperOp_NotEqual, false);
2132+ }
2133+ else
2134+ {
2135+ instr->Remove();
2136+ }
2137+ }
21202138 else
21212139 {
21222140 this->LowerBrCMem(instr, IR::HelperOp_NotEqual, false, false /*isHelper*/);
@@ -19346,6 +19364,178 @@ Lowerer::GenerateIsBuiltinRecyclableObject(IR::RegOpnd *regOpnd, IR::Instr *inse
1934619364 return typeRegOpnd;
1934719365}
1934819366
19367+ bool Lowerer::GenerateFastBrEqBoolInt(IR::BranchInstr * instrBranch, bool *pNeedHelper)
19368+ {
19369+ IR::Opnd *src1 = instrBranch->GetSrc1();
19370+ IR::Opnd *src2 = instrBranch->GetSrc2();
19371+ IR::LabelInstr *targetInstr = instrBranch->GetTarget();
19372+
19373+ IR::LabelInstr *labelFalse = instrBranch->GetOrCreateContinueLabel();
19374+ IR::LabelInstr *labelHelper = nullptr;
19375+
19376+ *pNeedHelper = true;
19377+
19378+ if (!(src1 && src2))
19379+ {
19380+ return false;
19381+ }
19382+ // Normallize for orderings
19383+ IR::Opnd *srcbool = nullptr;
19384+ IR::Opnd *srcint = nullptr;
19385+ if (src1->GetValueType().IsLikelyBoolean() && src2->GetValueType().IsLikelyTaggedInt())
19386+ {
19387+ srcbool = src1;
19388+ srcint = src2;
19389+ }
19390+ else if (src1->GetValueType().IsLikelyTaggedInt() && src2->GetValueType().IsLikelyBoolean())
19391+ {
19392+ srcint = src1;
19393+ srcbool = src2;
19394+ }
19395+ else
19396+ {
19397+ return false;
19398+ }
19399+ Assert(srcbool && srcint);
19400+
19401+ // If either instruction is constant, we can simplify the check. If both are constant, we can eliminate it
19402+ bool srcintconst = false;
19403+ bool srcintconstval = false;
19404+ bool srcboolconst = false;
19405+ bool srcboolconstval = false;
19406+ if (srcint->IsIntConstOpnd())
19407+ {
19408+ IR::IntConstOpnd * constsrcint = srcint->AsIntConstOpnd();
19409+ IntConstType constintval = constsrcint->GetValue();
19410+ srcintconst = true;
19411+ srcintconstval = constintval != 0;
19412+ }
19413+ else if (srcint->IsAddrOpnd())
19414+ {
19415+ IR::AddrOpnd * addrsrcint = srcint->AsAddrOpnd();
19416+ if (!(addrsrcint && addrsrcint->IsVar() && Js::TaggedInt::Is(addrsrcint->m_address)))
19417+ {
19418+ return false;
19419+ }
19420+ int32 value = Js::TaggedInt::ToInt32(addrsrcint->m_address);
19421+ srcintconst = true;
19422+ srcintconstval = value != 0;
19423+ }
19424+ else if (srcint->IsConstOpnd())
19425+ {
19426+ // Not handled yet
19427+ return false;
19428+ }
19429+ if (srcbool->IsIntConstOpnd())
19430+ {
19431+ Assert(srcbool->IsIntConstOpnd());
19432+ IR::IntConstOpnd * constsrcbool = srcbool->AsIntConstOpnd();
19433+ IntConstType constintval = constsrcbool->GetValue();
19434+ srcboolconst = true;
19435+ srcboolconstval = constintval != 0;
19436+ }
19437+ else if (srcbool->IsAddrOpnd())
19438+ {
19439+ IR::AddrOpnd * addrsrcbool = srcint->AsAddrOpnd();
19440+ if (!(addrsrcbool && addrsrcbool->IsVar() && Js::TaggedInt::Is(addrsrcbool->m_address)))
19441+ {
19442+ return false;
19443+ }
19444+ int32 value = Js::TaggedInt::ToInt32(addrsrcbool->m_address);
19445+ srcintconst = true;
19446+ srcintconstval = value != 0;
19447+ }
19448+ else if (srcbool->IsConstOpnd())
19449+ {
19450+ // Not handled yet
19451+ return false;
19452+ }
19453+
19454+ // Do these checks here, since that way we avoid emitting instructions before exiting earlier
19455+ if (srcint->GetValueType().IsTaggedInt() && srcbool->GetValueType().IsBoolean()) {
19456+ // ok, we know the types, so no helper needed
19457+ *pNeedHelper = false;
19458+ }
19459+ else
19460+ {
19461+ labelHelper = IR::LabelInstr::New(Js::OpCode::Label, this->m_func, true);
19462+ // check the types and jump to the helper if incorrect
19463+ if (!srcint->IsConstOpnd() && !srcint->GetValueType().IsTaggedInt())
19464+ {
19465+ this->m_lowererMD.GenerateObjectTest(srcint->AsRegOpnd(), instrBranch, labelHelper, false);
19466+ this->m_lowererMD.GenerateSmIntTest(srcint->AsRegOpnd(), instrBranch, labelHelper, nullptr, true);
19467+ // figure out how to check that it's an int efficiently at runtime
19468+ }
19469+ if (!srcbool->IsConstOpnd() && !srcbool->GetValueType().IsBoolean())
19470+ {
19471+ this->m_lowererMD.GenerateObjectTest(srcbool->AsRegOpnd(), instrBranch, labelHelper, false);
19472+ this->m_lowererMD.GenerateJSBooleanTest(srcbool->AsRegOpnd(), instrBranch, labelHelper, false);
19473+ }
19474+ }
19475+
19476+ // Now that we've checked the types, we can lower some instructions to quickly do the check
19477+ if (srcintconst && srcboolconst)
19478+ {
19479+ IR::LabelInstr * target = (instrBranch->m_opcode == Js::OpCode::BrEq_A || instrBranch->m_opcode == Js::OpCode::BrNotNeq_A) == (srcintconstval == srcboolconstval) ? targetInstr : labelFalse;
19480+ instrBranch->InsertBefore(IR::BranchInstr::New(LowererMD::MDUncondBranchOpcode, target, this->m_func));
19481+ // we don't need to emit the helper label
19482+ return true;
19483+ }
19484+ else if (!srcintconst && !srcboolconst)
19485+ {
19486+ IR::LabelInstr * firstTrue = IR::LabelInstr::New(Js::OpCode::Label, this->m_func);
19487+ IR::LabelInstr * firstFalse = IR::LabelInstr::New(Js::OpCode::Label, this->m_func);
19488+ this->m_lowererMD.GenerateTaggedZeroTest(srcint->AsRegOpnd(), instrBranch, firstFalse);
19489+ instrBranch->InsertBefore(firstTrue);
19490+ InsertCompareBranch(
19491+ srcbool,
19492+ LoadLibraryValueOpnd(instrBranch, LibraryValue::ValueTrue),
19493+ instrBranch->m_opcode,
19494+ targetInstr,
19495+ instrBranch);
19496+ instrBranch->InsertBefore(IR::BranchInstr::New(LowererMD::MDUncondBranchOpcode, labelFalse, this->m_func));
19497+ instrBranch->InsertBefore(firstFalse);
19498+ InsertCompareBranch(
19499+ srcbool,
19500+ LoadLibraryValueOpnd(instrBranch, LibraryValue::ValueFalse),
19501+ instrBranch->m_opcode,
19502+ targetInstr,
19503+ instrBranch);
19504+ instrBranch->InsertBefore(IR::BranchInstr::New(LowererMD::MDUncondBranchOpcode, labelFalse, this->m_func));
19505+ }
19506+ else if (srcintconst)
19507+ {
19508+ LibraryValue intval = srcintconstval ? LibraryValue::ValueTrue : LibraryValue::ValueFalse;
19509+ InsertCompareBranch(
19510+ srcbool,
19511+ LoadLibraryValueOpnd(instrBranch, intval),
19512+ instrBranch->m_opcode,
19513+ targetInstr,
19514+ instrBranch);
19515+ instrBranch->InsertBefore(IR::BranchInstr::New(LowererMD::MDUncondBranchOpcode, labelFalse, this->m_func));
19516+ }
19517+ else if (srcboolconst)
19518+ {
19519+ bool iseq = instrBranch->m_opcode == Js::OpCode::BrEq_A || instrBranch->m_opcode == Js::OpCode::BrNotNeq_A;
19520+ bool followbranchontrue = (iseq == srcboolconstval);
19521+ if (followbranchontrue)
19522+ {
19523+ this->m_lowererMD.GenerateTaggedZeroTest(srcint->AsRegOpnd(), instrBranch, labelFalse);
19524+ instrBranch->InsertBefore(IR::BranchInstr::New(LowererMD::MDUncondBranchOpcode, targetInstr, this->m_func));
19525+ }
19526+ else
19527+ {
19528+ this->m_lowererMD.GenerateTaggedZeroTest(srcint->AsRegOpnd(), instrBranch, targetInstr);
19529+ instrBranch->InsertBefore(IR::BranchInstr::New(LowererMD::MDUncondBranchOpcode, labelFalse, this->m_func));
19530+ }
19531+ }
19532+ if (*pNeedHelper)
19533+ {
19534+ instrBranch->InsertBefore(labelHelper);
19535+ }
19536+ return true;
19537+ }
19538+
1934919539bool Lowerer::GenerateFastBrEqLikely(IR::BranchInstr * instrBranch, bool *pNeedHelper)
1935019540{
1935119541 IR::Opnd *src1 = instrBranch->GetSrc1();
0 commit comments