From 16c09dcc8eb414d6003b96e917039de5ab7c424c Mon Sep 17 00:00:00 2001 From: Sergey Andreenko Date: Fri, 29 Jun 2018 13:38:44 -0700 Subject: [PATCH] optimize fgMorphTree for GenTreeArgList (dotnet/coreclr#18582) * add fgMorphArgList * hide the call inside fgMorphSmpOp * fix grammar mistakes Commit migrated from https://github.com/dotnet/coreclr/commit/f3da13e0661a95cc7a7c148e816af7040f98c748 --- src/coreclr/src/jit/compiler.h | 1 + src/coreclr/src/jit/morph.cpp | 64 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/src/coreclr/src/jit/compiler.h b/src/coreclr/src/jit/compiler.h index eb92395..7de9440 100644 --- a/src/coreclr/src/jit/compiler.h +++ b/src/coreclr/src/jit/compiler.h @@ -4906,6 +4906,7 @@ private: GenTree* fgUnwrapProxy(GenTree* objRef); GenTreeFieldList* fgMorphLclArgToFieldlist(GenTreeLclVarCommon* lcl); GenTreeCall* fgMorphArgs(GenTreeCall* call); + GenTreeArgList* fgMorphArgList(GenTreeArgList* args, MorphAddrContext* mac); void fgMakeOutgoingStructArgCopy(GenTreeCall* call, GenTree* args, diff --git a/src/coreclr/src/jit/morph.cpp b/src/coreclr/src/jit/morph.cpp index 5b7818b..d750d22 100644 --- a/src/coreclr/src/jit/morph.cpp +++ b/src/coreclr/src/jit/morph.cpp @@ -11875,6 +11875,9 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac) } break; #endif + case GT_LIST: + // Special handling for the arg list. + return fgMorphArgList(tree->AsArgList(), mac); default: break; @@ -18902,3 +18905,64 @@ bool Compiler::fgCheckStmtAfterTailCall() } return nextMorphStmt == nullptr; } + +//------------------------------------------------------------------------ +// fgMorphArgList: morph argument list tree without recursion. +// +// Arguments: +// args - argument list tree to morph; +// mac - morph address context, used to morph children. +// +// Return Value: +// morphed argument list. +// +GenTreeArgList* Compiler::fgMorphArgList(GenTreeArgList* args, MorphAddrContext* mac) +{ + // Use a non-recursive algorithm that morphs all actual list values, + // memorizes the last node for each effect flag and resets + // them during the second iteration. + constexpr int numberOfTrackedFlags = 5; + constexpr unsigned trackedFlags[numberOfTrackedFlags] = {GTF_ASG, GTF_CALL, GTF_EXCEPT, GTF_GLOB_REF, + GTF_ORDER_SIDEEFF}; + static_assert_no_msg((trackedFlags[0] | trackedFlags[1] | trackedFlags[2] | trackedFlags[3] | trackedFlags[4]) == + GTF_ALL_EFFECT); + + GenTree* memorizedLastNodes[numberOfTrackedFlags] = {nullptr}; + + for (GenTreeArgList* listNode = args; listNode != nullptr; listNode = listNode->Rest()) + { + // Morph actual list values. + GenTree*& arg = listNode->Current(); + arg = fgMorphTree(arg, mac); + + // Remember the last list node with each flag. + for (int i = 0; i < numberOfTrackedFlags; ++i) + { + if ((arg->gtFlags & trackedFlags[i]) != 0) + { + memorizedLastNodes[i] = listNode; + } + } + } + + for (GenTreeArgList* listNode = args; listNode != nullptr; listNode = listNode->Rest()) + { + // Clear all old effects from the list node. + listNode->gtFlags &= ~GTF_ALL_EFFECT; + + // Spread each flag to all list nodes (to the prefix) before the memorized last node. + for (int i = 0; i < numberOfTrackedFlags; ++i) + { + if (memorizedLastNodes[i] != nullptr) + { + listNode->gtFlags |= trackedFlags[i]; + } + if (listNode == memorizedLastNodes[i]) + { + memorizedLastNodes[i] = nullptr; + } + } + } + + return args; +} -- 2.7.4