Преглед изворни кода

Added test trace and phase

Jeffrey Lin пре 7 година
родитељ
комит
5d51cf6172

+ 1 - 1
lib/Backend/Func.cpp

@@ -66,7 +66,7 @@ Func::Func(JitArenaAllocator *alloc, JITTimeWorkItem * workItem,
     m_hasCalls(false),
     m_hasInlineArgsOpt(false),
     m_canDoInlineArgsOpt(true),
-    unoptableInlineArgCount(0),
+    unoptimizableArgumentsObjReference(0),
     m_doFastPaths(false),
     hasBailout(false),
     firstIRTemp(0),

+ 1 - 1
lib/Backend/Func.h

@@ -725,7 +725,7 @@ public:
     StackSym *          tempSymDouble;
     StackSym *          tempSymBool;
     uint32              loopCount;
-    uint32              unoptableInlineArgCount;
+    uint32              unoptimizableArgumentsObjReference;
     Js::ProfileId       callSiteIdInParentFunc;
     InlineeFrameInfo*   cachedInlineeFrameInfo;
     bool                m_hasCalls: 1; // This is more accurate compared to m_isLeaf

+ 29 - 18
lib/Backend/GlobOpt.cpp

@@ -1588,7 +1588,7 @@ GlobOpt::OptArguments(IR::Instr *instr)
         if (CurrentBlockData()->IsArgumentsOpnd(src1))
         {
             instr->usesStackArgumentsObject = true;
-            instr->m_func->unoptableInlineArgCount++;
+            instr->m_func->unoptimizableArgumentsObjReference++;
         }
 
         if (CurrentBlockData()->IsArgumentsOpnd(src1) &&
@@ -1608,7 +1608,7 @@ GlobOpt::OptArguments(IR::Instr *instr)
                     if (builtinFunction == Js::BuiltinFunction::JavascriptFunction_Apply)
                     {
                         CurrentBlockData()->ClearArgumentsSym(src1->AsRegOpnd());
-                        instr->m_func->unoptableInlineArgCount--;
+                        instr->m_func->unoptimizableArgumentsObjReference--;
                     }
                 }
                 else if (builtinOpnd->IsRegOpnd())
@@ -1616,7 +1616,7 @@ GlobOpt::OptArguments(IR::Instr *instr)
                     if (builtinOpnd->AsRegOpnd()->m_sym->m_builtInIndex == Js::BuiltinFunction::JavascriptFunction_Apply)
                     {
                         CurrentBlockData()->ClearArgumentsSym(src1->AsRegOpnd());
-                        instr->m_func->unoptableInlineArgCount--;
+                        instr->m_func->unoptimizableArgumentsObjReference--;
                     }
                 }
             }
@@ -2449,7 +2449,7 @@ GlobOpt::OptInstr(IR::Instr *&instr, bool* isInstrRemoved)
     OptimizeChecks(instr);
     OptArraySrc(&instr, &src1Val, &src2Val);
     OptNewScObject(&instr, src1Val);
-    OptArgLenAndConst(instr, &src1Val);
+    OptStackArgLenAndConst(instr, &src1Val);
 
     instr = this->OptPeep(instr, src1Val, src2Val);
 
@@ -13206,15 +13206,21 @@ GlobOpt::OptArraySrc(IR::Instr ** const instrRef, Value ** src1Val, Value ** src
 }
 
 void
-GlobOpt::OptArgLenAndConst(IR::Instr* instr, Value** src1Val)
+GlobOpt::OptStackArgLenAndConst(IR::Instr* instr, Value** src1Val)
 {
-    if (instr->usesStackArgumentsObject && instr->IsInlined())
+    if (!PHASE_OFF(Js::StackArgLenConstOptPhase, instr->m_func) && instr->m_func->IsStackArgsEnabled() && instr->usesStackArgumentsObject && instr->IsInlined())
     {
         IR::Opnd* src1 = instr->GetSrc1();
-        auto replaceInstr = [&](IR::Opnd* newopnd, Js::OpCode opCode = Js::OpCode::Ld_A)
+        auto replaceInstr = [&](IR::Opnd* newopnd, Js::OpCode opcode)
         {
+            if (PHASE_TESTTRACE(Js::StackArgLenConstOptPhase, instr->m_func))
+            {
+                Output::Print(_u("Inlined function %s have replaced opcode %s with opcode %s for stack arg optimization. \n"), instr->m_func->GetJITFunctionBody()->GetDisplayName(),
+                            Js::OpCodeUtil::GetOpCodeName(instr->m_opcode), Js::OpCodeUtil::GetOpCodeName(opcode));
+                Output::Flush();
+            }
             this->CaptureByteCodeSymUses(instr);
-            instr->m_opcode = opCode;
+            instr->m_opcode = opcode;
             instr->ReplaceSrc1(newopnd);
             if (instr->HasBailOutInfo())
             {
@@ -13229,10 +13235,9 @@ GlobOpt::OptArgLenAndConst(IR::Instr* instr, Value** src1Val)
             case Js::OpCode::LdLen_A:
             {
                 IR::AddrOpnd* newopnd = IR::AddrOpnd::New(Js::TaggedInt::ToVarUnchecked(instr->m_func->actualCount - 1), IR::AddrOpndKindConstantVar, instr->m_func);
-                replaceInstr(newopnd);
+                replaceInstr(newopnd, Js::OpCode::Ld_A);
                 break;
             }
-    
             case Js::OpCode::LdElemI_A:
             case Js::OpCode::TypeofElem:
             {
@@ -13251,26 +13256,32 @@ GlobOpt::OptArgLenAndConst(IR::Instr* instr, Value** src1Val)
                         }
                         return false;
                     });
+
+                    Js::OpCode replacementOpcode;
+                    if (instr->m_opcode == Js::OpCode::TypeofElem)
+                    {
+                        replacementOpcode = Js::OpCode::Typeof;
+                    }
+                    else
+                    {
+                        replacementOpcode = Js::OpCode::Ld_A;
+                    }
+
                     // If we cannot find the right instruction. I.E. When calling arguments[2] and no arguments were passed to the func
                     if (defInstr == nullptr) 
                     {
                         IR::Opnd * undefined = IR::AddrOpnd::New(instr->m_func->GetScriptContextInfo()->GetUndefinedAddr(), IR::AddrOpndKindDynamicVar, instr->m_func, true);
                         undefined->SetValueType(ValueType::Undefined);
-                        replaceInstr(undefined);
+                        replaceInstr(undefined, replacementOpcode);
                     }
                     else
                     {
-                        if (instr->m_opcode == Js::OpCode::TypeofElem) {
-                            replaceInstr(defInstr->GetSrc1(), Js::OpCode::Typeof);
-                        }
-                        else {
-                            replaceInstr(defInstr->GetSrc1());
-                        }
+                        replaceInstr(defInstr->GetSrc1(), replacementOpcode);
                     }   
                 }
                 else
                 {
-                    instr->m_func->unoptableInlineArgCount++;
+                    instr->m_func->unoptimizableArgumentsObjReference++;
                 }
                 break;
             }

+ 1 - 1
lib/Backend/GlobOpt.h

@@ -690,7 +690,7 @@ private:
     IR::Instr*              CreateBoundsCheckInstr(IR::Opnd* lowerBound, IR::Opnd* upperBound, int offset, IR::BailOutKind bailoutkind, BailOutInfo* bailoutInfo, Func* func);
     IR::Instr*              AttachBoundsCheckData(IR::Instr* instr, IR::Opnd* lowerBound, IR::Opnd* upperBound, int offset);
     void                    OptArraySrc(IR::Instr **const instrRef, Value ** src1Val, Value ** src2Val);
-    void                    OptArgLenAndConst(IR::Instr* instr, Value** src1Val);
+    void                    OptStackArgLenAndConst(IR::Instr* instr, Value** src1Val);
 
 private:
     void                    TrackIntSpecializedAddSubConstant(IR::Instr *const instr, const AddSubConstantInfo *const addSubConstantInfo, Value *const dstValue, const bool updateSourceBounds);

+ 9 - 11
lib/Backend/GlobOptBailOut.cpp

@@ -482,12 +482,14 @@ GlobOpt::CaptureByteCodeSymUses(IR::Instr * instr)
 void
 GlobOpt::ProcessInlineeEnd(IR::Instr* instr)
 {
-    if (instr->m_func->hasArgLenAndConstOpt && instr->m_func->unoptableInlineArgCount == 0)
+    if (!PHASE_OFF(Js::StackArgLenConstOptPhase, instr->m_func) && instr->m_func->IsStackArgsEnabled()
+        && instr->m_func->hasArgLenAndConstOpt && instr->m_func->unoptimizableArgumentsObjReference == 0)
     {
         instr->m_func->hasUnoptimizedArgumentsAccess = false;
         if (DoInlineArgsOpt(instr->m_func))
         {
             instr->m_func->m_hasInlineArgsOpt = true;
+            Assert(instr->m_func->cachedInlineeFrameInfo);
             instr->m_func->frameInfo = instr->m_func->cachedInlineeFrameInfo;
         }
     }
@@ -588,23 +590,19 @@ GlobOpt::TrackCalls(IR::Instr * instr)
         this->func->UpdateMaxInlineeArgOutSize(this->currentBlock->globOptData.inlinedArgOutSize);
         this->EndTrackCall(instr);
 
-        auto createFrameInfo = [&](Func* inlineeFunc)
-        {
-            InlineeFrameInfo* frameInfo = InlineeFrameInfo::New(inlineeFunc->m_alloc);
-            frameInfo->floatSyms = CurrentBlockData()->liveFloat64Syms->CopyNew(this->alloc);
-            frameInfo->intSyms = CurrentBlockData()->liveInt32Syms->MinusNew(CurrentBlockData()->liveLossyInt32Syms, this->alloc);
-            frameInfo->varSyms = CurrentBlockData()->liveVarSyms->CopyNew(this->alloc);
-            return frameInfo;
-        };
+        InlineeFrameInfo* inlineeFrameInfo = InlineeFrameInfo::New(instr->m_func->m_alloc);
+        inlineeFrameInfo->floatSyms = CurrentBlockData()->liveFloat64Syms->CopyNew(this->alloc);
+        inlineeFrameInfo->intSyms = CurrentBlockData()->liveInt32Syms->MinusNew(CurrentBlockData()->liveLossyInt32Syms, this->alloc);
+        inlineeFrameInfo->varSyms = CurrentBlockData()->liveVarSyms->CopyNew(this->alloc);
 
         if (DoInlineArgsOpt(instr->m_func))
         {
             instr->m_func->m_hasInlineArgsOpt = true;
-            instr->m_func->frameInfo = createFrameInfo(func);
+            instr->m_func->frameInfo = inlineeFrameInfo;
         }
         else
         {
-            instr->m_func->cachedInlineeFrameInfo = createFrameInfo(instr->m_func);
+            instr->m_func->cachedInlineeFrameInfo = inlineeFrameInfo;
         }
         break;
     }    

+ 1 - 0
lib/Common/ConfigFlagsList.h

@@ -165,6 +165,7 @@ PHASE(All)
                 PHASE(CheckThis)
                 PHASE(StackArgOpt)
                 PHASE(StackArgFormalsOpt)
+                PHASE(StackArgLenConstOpt)
                 PHASE(IndirCopyProp)
                 PHASE(ArrayCheckHoist)
                     PHASE(ArrayMissingValueCheckHoist)

+ 8 - 0
test/Function/rlexe.xml

@@ -434,6 +434,14 @@
       <tags>exclude_dynapogo</tags>
     </default>
   </test>
+  <test>
+    <default>
+      <files>stackArgsLenConstOpt.js</files>
+      <compile-flags>-mic:1 -off:simpleJit -testtrace:StackArgLenConstOpt</compile-flags>
+      <tags>exclude_dynapogo,exclude_nonative,require_backend,exclude_forceserialized,exclude_arm64</tags>
+      <baseline>stackArgsLenConstOpt.baseline</baseline>
+    </default>
+  </test>
   <test>
     <default>
       <files>childCallsEvalJitLoopBody.js</files>

+ 5 - 0
test/Function/stackArgsLenConstOpt.baseline

@@ -0,0 +1,5 @@
+Inlined function x_min have replaced opcode LdLen_A with opcode Ld_A for stack arg optimization. 
+Inlined function x_min have replaced opcode LdElemI_A with opcode Ld_A for stack arg optimization. 
+Inlined function x_min have replaced opcode LdElemI_A with opcode Ld_A for stack arg optimization. 
+Inlined function x_min have replaced opcode LdElemI_A with opcode Ld_A for stack arg optimization. 
+pass

+ 22 - 0
test/Function/stackArgsLenConstOpt.js

@@ -0,0 +1,22 @@
+//-------------------------------------------------------------------------------------------------------
+// Copyright (C) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
+//-------------------------------------------------------------------------------------------------------
+
+function x_min() {
+    if (arguments.length < 3) {
+        if (arguments[0] < arguments[1]) return arguments[0];
+        else return arguments[1];
+    }
+    return 1;
+}
+
+function test0() {
+    x_min(15,2);
+}
+
+for (var i = 0; i < 100; i++) {
+    test0();
+}
+
+WScript.Echo("pass");