-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Improve performance on some post-minifier code. #1682
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve performance on some post-minifier code. #1682
Conversation
|
Hi @Penguinwizzard, I'm your friendly neighborhood Microsoft Pull Request Bot (You can call me MSBOT). Thanks for your contribution!
TTYL, MSBOT; |
lib/Backend/Lower.cpp
Outdated
| this->LowerBrCMem(instr, IR::HelperOp_Equal, false); | ||
| } | ||
| } | ||
| else if (this->GenerateFastBrEqBoolInt(instr->AsBranchInstr(), &needHelper)) |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
|
What kind of perf improvements did you see? |
|
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. |
d10aca7 to
c790720
Compare
|
@dotnet-bot test Ubuntu ubuntu_linux_debug_static please |
lib/Backend/Lower.cpp
Outdated
| typeOpnd = instrSrc2; | ||
| idOpnd = instrSrc1; | ||
| } | ||
| if (typeOpnd && idOpnd) |
There was a problem hiding this comment.
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.
lib/Backend/GlobOpt.cpp
Outdated
| || (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; |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
lib/Backend/GlobOpt.cpp
Outdated
| // 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()) { |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
lib/Backend/GlobOpt.cpp
Outdated
| && 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; |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
lib/Backend/BackwardPass.cpp
Outdated
| // 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) |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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...
There was a problem hiding this comment.
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.
f4a53b1 to
2ae533b
Compare
| uint8 hasCall:1; | ||
| uint8 isVisited:1; | ||
| uint8 isAirLockCompensationBlock:1; | ||
| uint8 beginsBailOnNoProfile:1; |
There was a problem hiding this comment.
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
lib/Backend/GlobOpt.cpp
Outdated
| ValueInfo *src1ValInfo = src1Val->GetValueInfo(); | ||
| ValueInfo *src2ValInfo = src2Val->GetValueInfo(); | ||
| if ( | ||
| (src1ValInfo->IsNumber() && src1Var && src2ValInfo->IsBoolean() && src1Var != Js::TaggedInt::ToVarUnchecked(0) && src1Var != Js::TaggedInt::ToVarUnchecked(1)) || |
There was a problem hiding this comment.
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?
lib/Backend/GlobOpt.cpp
Outdated
| 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)) |
There was a problem hiding this comment.
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; | ||
| } |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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); | ||
| } |
There was a problem hiding this comment.
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; | ||
| } |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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
lib/Backend/Lower.cpp
Outdated
| } | ||
| if (srcBool->IsIntConstOpnd()) | ||
| { | ||
| Assert(srcBool->IsIntConstOpnd()); |
There was a problem hiding this comment.
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?
lib/Backend/Lower.cpp
Outdated
| else if (srcIntConst && srcBoolConst) | ||
| { | ||
| // If both arguments are constant, we can statically determine the result. | ||
| bool sameval = srcIntConstVal == srcBoolConstVal; |
There was a problem hiding this comment.
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
lib/Backend/Lower.cpp
Outdated
| 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); |
There was a problem hiding this comment.
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
2ae533b to
5a44314
Compare
5a44314 to
211ee15
Compare
211ee15 to
add6acf
Compare
Running a minifier on some common benchmarks revealed areas where we could improve our performance.