Skip to content

Commit c790720

Browse files
Lower a fast-path for int-bool equality comparisons.
1 parent a92f792 commit c790720

File tree

2 files changed

+191
-0
lines changed

2 files changed

+191
-0
lines changed

lib/Backend/Lower.cpp

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
1934919539
bool Lowerer::GenerateFastBrEqLikely(IR::BranchInstr * instrBranch, bool *pNeedHelper)
1935019540
{
1935119541
IR::Opnd *src1 = instrBranch->GetSrc1();

lib/Backend/Lower.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,7 @@ class Lowerer
246246
bool GenerateFastBrSrNeq(IR::Instr * instr, IR::Instr ** pInstrPrev);
247247
IR::BranchInstr* GenerateFastBrConst(IR::BranchInstr *branchInstr, IR::Opnd * constOpnd, bool isEqual);
248248
bool GenerateFastCondBranch(IR::BranchInstr * instrBranch, bool *pIsHelper);
249+
bool GenerateFastBrEqBoolInt(IR::BranchInstr * instrBranch, bool *pIsHelper);
249250
bool GenerateFastBrEqLikely(IR::BranchInstr * instrBranch, bool *pNeedHelper);
250251
bool GenerateFastBooleanAndObjectEqLikely(IR::Instr * instr, IR::Opnd *src1, IR::Opnd *src2, IR::LabelInstr * labelHelper, IR::LabelInstr * labelEqualLikely, bool *pNeedHelper);
251252
bool GenerateFastCmEqLikely(IR::Instr * instr, bool *pNeedHelper);

0 commit comments

Comments
 (0)