Skip to content

Commit 0617d9f

Browse files
committed
[MERGE #5733 @yullin-ms] Inline Arg Optimization
Merge pull request #5733 from yullin-ms:argLenAndConstOptPhaseTwo This is to do inline arg optimization when we do argument length and argument constant optimizations
2 parents 3321ead + 5d51cf6 commit 0617d9f

File tree

9 files changed

+99
-16
lines changed

9 files changed

+99
-16
lines changed

lib/Backend/Func.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ Func::Func(JitArenaAllocator *alloc, JITTimeWorkItem * workItem,
6666
m_hasCalls(false),
6767
m_hasInlineArgsOpt(false),
6868
m_canDoInlineArgsOpt(true),
69+
unoptimizableArgumentsObjReference(0),
6970
m_doFastPaths(false),
7071
hasBailout(false),
7172
firstIRTemp(0),
@@ -108,6 +109,7 @@ Func::Func(JitArenaAllocator *alloc, JITTimeWorkItem * workItem,
108109
loopCount(0),
109110
callSiteIdInParentFunc(callSiteIdInParentFunc),
110111
isGetterSetter(isGetterSetter),
112+
cachedInlineeFrameInfo(nullptr),
111113
frameInfo(nullptr),
112114
isTJLoopBody(false),
113115
m_nativeCodeDataSym(nullptr),

lib/Backend/Func.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -725,7 +725,9 @@ static const unsigned __int64 c_debugFillPattern8 = 0xcececececececece;
725725
StackSym * tempSymDouble;
726726
StackSym * tempSymBool;
727727
uint32 loopCount;
728+
uint32 unoptimizableArgumentsObjReference;
728729
Js::ProfileId callSiteIdInParentFunc;
730+
InlineeFrameInfo* cachedInlineeFrameInfo;
729731
bool m_hasCalls: 1; // This is more accurate compared to m_isLeaf
730732
bool m_hasInlineArgsOpt : 1;
731733
bool m_doFastPaths : 1;

lib/Backend/GlobOpt.cpp

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1588,6 +1588,7 @@ GlobOpt::OptArguments(IR::Instr *instr)
15881588
if (CurrentBlockData()->IsArgumentsOpnd(src1))
15891589
{
15901590
instr->usesStackArgumentsObject = true;
1591+
instr->m_func->unoptimizableArgumentsObjReference++;
15911592
}
15921593

15931594
if (CurrentBlockData()->IsArgumentsOpnd(src1) &&
@@ -1607,13 +1608,15 @@ GlobOpt::OptArguments(IR::Instr *instr)
16071608
if (builtinFunction == Js::BuiltinFunction::JavascriptFunction_Apply)
16081609
{
16091610
CurrentBlockData()->ClearArgumentsSym(src1->AsRegOpnd());
1611+
instr->m_func->unoptimizableArgumentsObjReference--;
16101612
}
16111613
}
16121614
else if (builtinOpnd->IsRegOpnd())
16131615
{
16141616
if (builtinOpnd->AsRegOpnd()->m_sym->m_builtInIndex == Js::BuiltinFunction::JavascriptFunction_Apply)
16151617
{
16161618
CurrentBlockData()->ClearArgumentsSym(src1->AsRegOpnd());
1619+
instr->m_func->unoptimizableArgumentsObjReference--;
16171620
}
16181621
}
16191622
}
@@ -2446,7 +2449,7 @@ GlobOpt::OptInstr(IR::Instr *&instr, bool* isInstrRemoved)
24462449
OptimizeChecks(instr);
24472450
OptArraySrc(&instr, &src1Val, &src2Val);
24482451
OptNewScObject(&instr, src1Val);
2449-
OptArgLenAndConst(instr, &src1Val);
2452+
OptStackArgLenAndConst(instr, &src1Val);
24502453

24512454
instr = this->OptPeep(instr, src1Val, src2Val);
24522455

@@ -13203,15 +13206,21 @@ GlobOpt::OptArraySrc(IR::Instr ** const instrRef, Value ** src1Val, Value ** src
1320313206
}
1320413207

1320513208
void
13206-
GlobOpt::OptArgLenAndConst(IR::Instr* instr, Value** src1Val)
13209+
GlobOpt::OptStackArgLenAndConst(IR::Instr* instr, Value** src1Val)
1320713210
{
13208-
if (instr->usesStackArgumentsObject && instr->IsInlined())
13211+
if (!PHASE_OFF(Js::StackArgLenConstOptPhase, instr->m_func) && instr->m_func->IsStackArgsEnabled() && instr->usesStackArgumentsObject && instr->IsInlined())
1320913212
{
1321013213
IR::Opnd* src1 = instr->GetSrc1();
13211-
auto replaceInstr = [&](IR::Opnd* newopnd)
13214+
auto replaceInstr = [&](IR::Opnd* newopnd, Js::OpCode opcode)
1321213215
{
13216+
if (PHASE_TESTTRACE(Js::StackArgLenConstOptPhase, instr->m_func))
13217+
{
13218+
Output::Print(_u("Inlined function %s have replaced opcode %s with opcode %s for stack arg optimization. \n"), instr->m_func->GetJITFunctionBody()->GetDisplayName(),
13219+
Js::OpCodeUtil::GetOpCodeName(instr->m_opcode), Js::OpCodeUtil::GetOpCodeName(opcode));
13220+
Output::Flush();
13221+
}
1321313222
this->CaptureByteCodeSymUses(instr);
13214-
instr->m_opcode = Js::OpCode::Ld_A;
13223+
instr->m_opcode = opcode;
1321513224
instr->ReplaceSrc1(newopnd);
1321613225
if (instr->HasBailOutInfo())
1321713226
{
@@ -13226,11 +13235,11 @@ GlobOpt::OptArgLenAndConst(IR::Instr* instr, Value** src1Val)
1322613235
case Js::OpCode::LdLen_A:
1322713236
{
1322813237
IR::AddrOpnd* newopnd = IR::AddrOpnd::New(Js::TaggedInt::ToVarUnchecked(instr->m_func->actualCount - 1), IR::AddrOpndKindConstantVar, instr->m_func);
13229-
replaceInstr(newopnd);
13238+
replaceInstr(newopnd, Js::OpCode::Ld_A);
1323013239
break;
1323113240
}
13232-
1323313241
case Js::OpCode::LdElemI_A:
13242+
case Js::OpCode::TypeofElem:
1323413243
{
1323513244
IR::IndirOpnd* indirOpndSrc1 = src1->AsIndirOpnd();
1323613245
if (!indirOpndSrc1->GetIndexOpnd())
@@ -13247,17 +13256,32 @@ GlobOpt::OptArgLenAndConst(IR::Instr* instr, Value** src1Val)
1324713256
}
1324813257
return false;
1324913258
});
13259+
13260+
Js::OpCode replacementOpcode;
13261+
if (instr->m_opcode == Js::OpCode::TypeofElem)
13262+
{
13263+
replacementOpcode = Js::OpCode::Typeof;
13264+
}
13265+
else
13266+
{
13267+
replacementOpcode = Js::OpCode::Ld_A;
13268+
}
13269+
1325013270
// If we cannot find the right instruction. I.E. When calling arguments[2] and no arguments were passed to the func
1325113271
if (defInstr == nullptr)
1325213272
{
1325313273
IR::Opnd * undefined = IR::AddrOpnd::New(instr->m_func->GetScriptContextInfo()->GetUndefinedAddr(), IR::AddrOpndKindDynamicVar, instr->m_func, true);
1325413274
undefined->SetValueType(ValueType::Undefined);
13255-
replaceInstr(undefined);
13275+
replaceInstr(undefined, replacementOpcode);
1325613276
}
1325713277
else
1325813278
{
13259-
replaceInstr(defInstr->GetSrc1());
13260-
}
13279+
replaceInstr(defInstr->GetSrc1(), replacementOpcode);
13280+
}
13281+
}
13282+
else
13283+
{
13284+
instr->m_func->unoptimizableArgumentsObjReference++;
1326113285
}
1326213286
break;
1326313287
}

lib/Backend/GlobOpt.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -690,7 +690,7 @@ class GlobOpt
690690
IR::Instr* CreateBoundsCheckInstr(IR::Opnd* lowerBound, IR::Opnd* upperBound, int offset, IR::BailOutKind bailoutkind, BailOutInfo* bailoutInfo, Func* func);
691691
IR::Instr* AttachBoundsCheckData(IR::Instr* instr, IR::Opnd* lowerBound, IR::Opnd* upperBound, int offset);
692692
void OptArraySrc(IR::Instr **const instrRef, Value ** src1Val, Value ** src2Val);
693-
void OptArgLenAndConst(IR::Instr* instr, Value** src1Val);
693+
void OptStackArgLenAndConst(IR::Instr* instr, Value** src1Val);
694694

695695
private:
696696
void TrackIntSpecializedAddSubConstant(IR::Instr *const instr, const AddSubConstantInfo *const addSubConstantInfo, Value *const dstValue, const bool updateSourceBounds);

lib/Backend/GlobOptBailOut.cpp

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,18 @@ GlobOpt::CaptureByteCodeSymUses(IR::Instr * instr)
482482
void
483483
GlobOpt::ProcessInlineeEnd(IR::Instr* instr)
484484
{
485+
if (!PHASE_OFF(Js::StackArgLenConstOptPhase, instr->m_func) && instr->m_func->IsStackArgsEnabled()
486+
&& instr->m_func->hasArgLenAndConstOpt && instr->m_func->unoptimizableArgumentsObjReference == 0)
487+
{
488+
instr->m_func->hasUnoptimizedArgumentsAccess = false;
489+
if (DoInlineArgsOpt(instr->m_func))
490+
{
491+
instr->m_func->m_hasInlineArgsOpt = true;
492+
Assert(instr->m_func->cachedInlineeFrameInfo);
493+
instr->m_func->frameInfo = instr->m_func->cachedInlineeFrameInfo;
494+
}
495+
}
496+
485497
if (instr->m_func->m_hasInlineArgsOpt)
486498
{
487499
RecordInlineeFrameInfo(instr);
@@ -570,23 +582,30 @@ GlobOpt::TrackCalls(IR::Instr * instr)
570582
}
571583

572584
case Js::OpCode::InlineeStart:
585+
{
573586
Assert(instr->m_func->GetParentFunc() == this->currentBlock->globOptData.curFunc);
574587
Assert(instr->m_func->GetParentFunc());
575588
this->currentBlock->globOptData.curFunc = instr->m_func;
576589

577590
this->func->UpdateMaxInlineeArgOutSize(this->currentBlock->globOptData.inlinedArgOutSize);
578591
this->EndTrackCall(instr);
579592

593+
InlineeFrameInfo* inlineeFrameInfo = InlineeFrameInfo::New(instr->m_func->m_alloc);
594+
inlineeFrameInfo->floatSyms = CurrentBlockData()->liveFloat64Syms->CopyNew(this->alloc);
595+
inlineeFrameInfo->intSyms = CurrentBlockData()->liveInt32Syms->MinusNew(CurrentBlockData()->liveLossyInt32Syms, this->alloc);
596+
inlineeFrameInfo->varSyms = CurrentBlockData()->liveVarSyms->CopyNew(this->alloc);
597+
580598
if (DoInlineArgsOpt(instr->m_func))
581599
{
582600
instr->m_func->m_hasInlineArgsOpt = true;
583-
InlineeFrameInfo* frameInfo = InlineeFrameInfo::New(func->m_alloc);
584-
instr->m_func->frameInfo = frameInfo;
585-
frameInfo->floatSyms = CurrentBlockData()->liveFloat64Syms->CopyNew(this->alloc);
586-
frameInfo->intSyms = CurrentBlockData()->liveInt32Syms->MinusNew(CurrentBlockData()->liveLossyInt32Syms, this->alloc);
587-
frameInfo->varSyms = CurrentBlockData()->liveVarSyms->CopyNew(this->alloc);
601+
instr->m_func->frameInfo = inlineeFrameInfo;
602+
}
603+
else
604+
{
605+
instr->m_func->cachedInlineeFrameInfo = inlineeFrameInfo;
588606
}
589607
break;
608+
}
590609

591610
case Js::OpCode::EndCallForPolymorphicInlinee:
592611
// Have this opcode mimic the functions of both InlineeStart and InlineeEnd in the bailout block of a polymorphic call inlined using fixed methods.

lib/Common/ConfigFlagsList.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ PHASE(All)
165165
PHASE(CheckThis)
166166
PHASE(StackArgOpt)
167167
PHASE(StackArgFormalsOpt)
168+
PHASE(StackArgLenConstOpt)
168169
PHASE(IndirCopyProp)
169170
PHASE(ArrayCheckHoist)
170171
PHASE(ArrayMissingValueCheckHoist)

test/Function/rlexe.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,14 @@
434434
<tags>exclude_dynapogo</tags>
435435
</default>
436436
</test>
437+
<test>
438+
<default>
439+
<files>stackArgsLenConstOpt.js</files>
440+
<compile-flags>-mic:1 -off:simpleJit -testtrace:StackArgLenConstOpt</compile-flags>
441+
<tags>exclude_dynapogo,exclude_nonative,require_backend,exclude_forceserialized,exclude_arm64</tags>
442+
<baseline>stackArgsLenConstOpt.baseline</baseline>
443+
</default>
444+
</test>
437445
<test>
438446
<default>
439447
<files>childCallsEvalJitLoopBody.js</files>
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Inlined function x_min have replaced opcode LdLen_A with opcode Ld_A for stack arg optimization.
2+
Inlined function x_min have replaced opcode LdElemI_A with opcode Ld_A for stack arg optimization.
3+
Inlined function x_min have replaced opcode LdElemI_A with opcode Ld_A for stack arg optimization.
4+
Inlined function x_min have replaced opcode LdElemI_A with opcode Ld_A for stack arg optimization.
5+
pass

test/Function/stackArgsLenConstOpt.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//-------------------------------------------------------------------------------------------------------
2+
// Copyright (C) Microsoft. All rights reserved.
3+
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
4+
//-------------------------------------------------------------------------------------------------------
5+
6+
function x_min() {
7+
if (arguments.length < 3) {
8+
if (arguments[0] < arguments[1]) return arguments[0];
9+
else return arguments[1];
10+
}
11+
return 1;
12+
}
13+
14+
function test0() {
15+
x_min(15,2);
16+
}
17+
18+
for (var i = 0; i < 100; i++) {
19+
test0();
20+
}
21+
22+
WScript.Echo("pass");

0 commit comments

Comments
 (0)