From f1d3282f27009c9c213365f70f6ae2e5b69872a9 Mon Sep 17 00:00:00 2001 From: Andy Ayers Date: Thu, 9 Nov 2017 17:07:12 -0800 Subject: JIT: look through GT_RET_EXPR when forming inline candidates If an inline candidate has args that come from calls that are inline candidates, the arg trees for the candidate may be GT_RET_EXPRs. Since the jit inlines in preorder, any arg inlines will have been resolved by the time we get to the candidate. So, the jit can look back through the GT_RET_EXPR to get a better handle on the actual arg tree. Doing this has several small benefits: * It short-circuits parts of the subsequent GT_RET_EXPR update and so saves a little bit of throughput. * It potentially allows for more streamlined arg passing since the actual node side effects may be less constraining than the placeholder effects on the GT_RET_EXPR (which must be "worst case"). * It may unblock inlines as actual arg values can be seen when evaluating the candidate for profitability. During testing I found cases where looking at the actual arg seemed to degrade information. This turned out to be a misuse of `argHasLdargaOp` to indicate that a caller-supplied argument was potentially locally aliased. This misuse was blocking type propagation when the actual arg tree was seen to be an aliasable local reference instead of the formerly opaque GT_RET_EXPR. To fix this, I split out the aliased arg case with a different flag. All that the jit needs to ensure in the aliased case is that it does not directly substitute the arg; the arg must be evaluated at the point of the call. The type of the actual can safely propagate to the arg as long as the arg itself is not modifiable. Added a utility for walking back through GT_RET_EXPRs and updated the other case where the jit was doing this to use the utility as well. Closes #14174. --- src/jit/gentree.h | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'src/jit/gentree.h') diff --git a/src/jit/gentree.h b/src/jit/gentree.h index 09ce220871..9082945e6a 100644 --- a/src/jit/gentree.h +++ b/src/jit/gentree.h @@ -1813,6 +1813,9 @@ public: inline GenTreePtr gtEffectiveVal(bool commaOnly = false); + // Tunnel through any GT_RET_EXPRs + inline GenTree* gtRetExprVal(); + // Return the child of this node if it is a GT_RELOAD or GT_COPY; otherwise simply return the node itself inline GenTree* gtSkipReloadOrCopy(); @@ -6130,6 +6133,33 @@ inline GenTreePtr GenTree::gtEffectiveVal(bool commaOnly) } } +//------------------------------------------------------------------------- +// gtRetExprVal - walk back through GT_RET_EXPRs +// +// Returns: +// tree representing return value from a successful inline, +// or original call for failed or yet to be determined inline. +// +// Notes: +// Multi-level inlines can form chains of GT_RET_EXPRs. +// This method walks back to the root of the chain. + +inline GenTree* GenTree::gtRetExprVal() +{ + GenTree* retExprVal = this; + for (;;) + { + if (retExprVal->gtOper == GT_RET_EXPR) + { + retExprVal = retExprVal->gtRetExpr.gtInlineCandidate; + } + else + { + return retExprVal; + } + } +} + inline GenTree* GenTree::gtSkipReloadOrCopy() { // There can be only one reload or copy (we can't have a reload/copy of a reload/copy) -- cgit v1.2.3