Skip to content

Conversation

@Penguinwizzard
Copy link
Contributor

Running a minifier on some common benchmarks revealed areas where we could improve our performance.

@msftclas
Copy link

msftclas commented Oct 3, 2016

Hi @Penguinwizzard, I'm your friendly neighborhood Microsoft Pull Request Bot (You can call me MSBOT). Thanks for your contribution!


It looks like you're a Microsoft contributor (Derek Morris). If you're full-time, we DON'T require a Contribution License Agreement. If you are a vendor, please DO sign the electronic Contribution License Agreement. It will take 2 minutes and there's no faxing! https://cla.microsoft.com.

TTYL, MSBOT;

this->LowerBrCMem(instr, IR::HelperOp_Equal, false);
}
}
else if (this->GenerateFastBrEqBoolInt(instr->AsBranchInstr(), &needHelper))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GenerateFastBrEqBoolInt [](start = 31, length = 23)

Should we also have this for CmEq_A and CmNeq_A as most of the code is reusable?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's definitely doable; I'll take a swing at it, hopefully it also proves effective.

@rajatd
Copy link
Contributor

rajatd commented Oct 3, 2016

What kind of perf improvements did you see?

@Penguinwizzard
Copy link
Contributor Author

The score of post-minifier octane navier-stokes.js improved ~30%, post-minifier mandreel.js improved ~22%, post-minifier splay.js improved ~24%, and a number of other tests posted smaller improvements. This doesn't impact the score on a non-minified version of octane though.

@Penguinwizzard
Copy link
Contributor Author

@dotnet-bot test Ubuntu ubuntu_linux_debug_static please
@dotnet-bot test Ubuntu ubuntu_linux_test please

typeOpnd = instrSrc2;
idOpnd = instrSrc1;
}
if (typeOpnd && idOpnd)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

null check for instrSrc1 and instrSrc2 above makes this check redundant.

@rajatd
Copy link
Contributor

rajatd commented Oct 10, 2016

@pleath @akroshg for bytecode changes

|| (src2 && src2->IsConstOpnd()))
&& bInstr->GetSrc1()->IsRegOpnd())
// These are used because we don't want to rely on src1 or src2 to always be the register/constant
IR::RegOpnd *regopnd = nullptr;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

regopnd [](start = 21, length = 7)

nit: please use camelCase for variable names.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

// These are used because we don't want to rely on src1 or src2 to always be the register/constant
IR::RegOpnd *regopnd = nullptr;
IR::Opnd *constopnd = nullptr;
if (!src2 && (instr->m_opcode == Js::OpCode::BrFalse_A || instr->m_opcode == Js::OpCode::BrTrue_A) && src1->IsRegOpnd()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: opening brace on the next line, as has been done in the rest of the file

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

&& bInstr->GetSrc1()->IsRegOpnd())
// These are used because we don't want to rely on src1 or src2 to always be the register/constant
IR::RegOpnd *regopnd = nullptr;
IR::Opnd *constopnd = nullptr;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

constopnd [](start = 18, length = 9)

what is constOpnd used for?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've removed that in the new revision, thanks; it was an artefact of how I ambidextrized the check.

// part of the block prefix, and put the bailonnoprofile immediately after them. This has the added benefit
// that we can still merge up blocks beginning with bailonnoprofile, even if they would otherwise not allow
// us to, due to the fact that these tmp declarations would be pre-empted by the higher-level bailout.
while (curNext->m_opcode == Js::OpCode::Ld_A && curNext->GetDst()->IsRegOpnd() && curNext->GetDst()->AsRegOpnd()->m_fgPeepTmp)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be cleaned up a bit it seems. The while condition is the same as the if, making the if unnecessary.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've restructured the code to be a single while loop, removing the extra copy of the condition.


// Move to top of block.
while(!curInstr->StartsBasicBlock())
while(!curInstr->StartsBasicBlock() && curInstr != instrNope)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nstrNope [](start = 56, length = 8)

The way I read this, if instrNope is set, it will always be == curInstr...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tracing the code seems to indicate that it has the desired effect; while they will be equal in cases where the BailOnNoProfile is already just under the Ld_A fgPeepTmps, in many cases there will be other instructions in between. In that case, instrNope serves as a second "start of block", at which the search back towards the start of the block should stop.

@Penguinwizzard Penguinwizzard force-pushed the closure_compiler branch 4 times, most recently from f4a53b1 to 2ae533b Compare November 9, 2016 22:35
uint8 hasCall:1;
uint8 isVisited:1;
uint8 isAirLockCompensationBlock:1;
uint8 beginsBailOnNoProfile:1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

beginsBailOnNoProfile [](start = 25, length = 21)

nit: consider changing the name to beginsWithBailOnNoProfile

ValueInfo *src1ValInfo = src1Val->GetValueInfo();
ValueInfo *src2ValInfo = src2Val->GetValueInfo();
if (
(src1ValInfo->IsNumber() && src1Var && src2ValInfo->IsBoolean() && src1Var != Js::TaggedInt::ToVarUnchecked(0) && src1Var != Js::TaggedInt::ToVarUnchecked(1)) ||
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we also fold a branch when we get a non-null constant var for the src which is definitely boolean and then compare the constant boolean with the constant number value of the other src?

ValueInfo *src2ValInfo = src2Val->GetValueInfo();
if (
(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))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I would refactor this condition (and the one above for BrEq_A) into a method.

// This opcode is not one of the ones that should be handled here.
return false;
break;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could make this part cleaner. Example,
switch (instr->m_opcode)
{
case Js::OpCode::BrSrEq_A:
case Js::OpCode::BrSrNotNeq_A:
case Js::OpCode::CmSrEq_A:
isStrict = true;
break;

case Js::OpCode::BrSrNeq_A:
case Js::OpCode::BrSrNotEq_A:
case Js::OpCode::CmSrNeq_A:
    isStrict = true;
case Js::OpCode::BrNeq_A:
case Js::OpCode::BrNotEq_A:
case Js::OpCode::CmNeq_A:
    isNeqOp = true;
    break;
}

And I would put an assert in the default case for unexpected opcode.

return false;
}

// If either instruction is constant, we can simplify the check. If both are constant, we can eliminate it
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instruction [](start = 17, length = 11)

nit: source

if (*pNeedHelper)
{
instr->InsertBefore(labelHelper);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rather have a wrapper for this function, have that wrapper pass the helper label to this function, insert the helper label when this function returns, and replace all callsites of this function with that helper. It would make using this function in other places easier.

{
srcIntConstVal = true;
srcIntIsBoolable = true;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This block shouldn't be required after @meg-gupta 's #1630

}
int32 value = Js::TaggedInt::ToInt32(addrSrcBool->m_address);
srcBoolConst = true;
srcBoolConstVal = value != 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This block shouldn't be required after @meg-gupta 's #1630

}
if (srcBool->IsIntConstOpnd())
{
Assert(srcBool->IsIntConstOpnd());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assert(srcBool->IsIntConstOpnd()); [](start = 8, length = 34)

redundant?

else if (srcIntConst && srcBoolConst)
{
// If both arguments are constant, we can statically determine the result.
bool sameval = srcIntConstVal == srcBoolConstVal;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sameval [](start = 13, length = 7)

nit: camel case

else if (!srcIntConst && !srcBoolConst)
{
// If neither is constant, we can still do a bit better than loading the helper
IR::LabelInstr * firstTrue = IR::LabelInstr::New(Js::OpCode::Label, this->m_func);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

firstTrue [](start = 25, length = 9)

no code seems to be branching to this label

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants