Skip to content

Commit

Permalink
Add comments and clean up getRuntimeLookupTree.
Browse files Browse the repository at this point in the history
  • Loading branch information
erozenfeld committed Mar 21, 2020
1 parent cc36784 commit 2f0cd3e
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 93 deletions.
4 changes: 4 additions & 0 deletions src/coreclr/src/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -2559,6 +2559,10 @@ class Compiler

GenTreeCall* gtNewHelperCallNode(unsigned helper, var_types type, GenTreeCall::Use* args = nullptr);

GenTreeCall* gtNewRuntimeLookupHelperCallNode(CORINFO_RUNTIME_LOOKUP* pRuntimeLookup,
GenTree* ctxTree,
void* compileTimeHandle);

GenTree* gtNewLclvNode(unsigned lnum, var_types type DEBUGARG(IL_OFFSETX ILoffs = BAD_IL_OFFSET));
GenTree* gtNewLclLNode(unsigned lnum, var_types type DEBUGARG(IL_OFFSETX ILoffs = BAD_IL_OFFSET));

Expand Down
22 changes: 22 additions & 0 deletions src/coreclr/src/jit/compiler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1125,6 +1125,28 @@ inline GenTreeCall* Compiler::gtNewHelperCallNode(unsigned helper, var_types typ
return result;
}

//------------------------------------------------------------------------------
// gtNewRuntimeLookupHelperCallNode : Helper to create a runtime lookup call helper node.
//
//
// Arguments:
// helper - Call helper
// type - Type of the node
// args - Call args
//
// Return Value:
// New CT_HELPER node

inline GenTreeCall* Compiler::gtNewRuntimeLookupHelperCallNode(CORINFO_RUNTIME_LOOKUP* pRuntimeLookup,
GenTree* ctxTree,
void* compileTimeHandle)
{
GenTree* argNode = gtNewIconEmbHndNode(pRuntimeLookup->signature, nullptr, GTF_ICON_TOKEN_HDL, compileTimeHandle);
GenTreeCall::Use* helperArgs = gtNewCallArgs(ctxTree, argNode);

return gtNewHelperCallNode(pRuntimeLookup->helper, TYP_I_IMPL, helperArgs);
}

//------------------------------------------------------------------------
// gtNewAllocObjNode: A little helper to create an object allocation node.
//
Expand Down
10 changes: 10 additions & 0 deletions src/coreclr/src/jit/gentree.h
Original file line number Diff line number Diff line change
Expand Up @@ -3503,31 +3503,40 @@ class TailCallSiteInfo
CORINFO_RESOLVED_TOKEN m_token;

public:
// Is the tailcall a callvirt instruction?
bool IsCallvirt()
{
return m_isCallvirt;
}

// Is the tailcall a calli instruction?
bool IsCalli()
{
return m_isCalli;
}

// Get the token of the callee
CORINFO_RESOLVED_TOKEN* GetToken()
{
assert(!IsCalli());
return &m_token;
}

// Get the signature of the callee
CORINFO_SIG_INFO* GetSig()
{
return &m_sig;
}

// Mark the tailcall as a calli with the given signature
void SetCalli(CORINFO_SIG_INFO* sig)
{
m_isCallvirt = false;
m_isCalli = true;
m_sig = *sig;
}

// Mark the tailcall as a callvirt with the given signature and token
void SetCallvirt(CORINFO_SIG_INFO* sig, CORINFO_RESOLVED_TOKEN* token)
{
m_isCallvirt = true;
Expand All @@ -3536,6 +3545,7 @@ class TailCallSiteInfo
m_token = *token;
}

// Mark the tailcall as a call with the given signature and token
void SetCall(CORINFO_SIG_INFO* sig, CORINFO_RESOLVED_TOKEN* token)
{
m_isCallvirt = false;
Expand Down
6 changes: 1 addition & 5 deletions src/coreclr/src/jit/importer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2035,11 +2035,7 @@ GenTree* Compiler::impRuntimeLookupToTree(CORINFO_RESOLVED_TOKEN* pResolvedToken
gtNewCallArgs(ctxTree), &pLookup->lookupKind);
}
#endif
GenTree* argNode =
gtNewIconEmbHndNode(pRuntimeLookup->signature, nullptr, GTF_ICON_TOKEN_HDL, compileTimeHandle);
GenTreeCall::Use* helperArgs = gtNewCallArgs(ctxTree, argNode);

return gtNewHelperCallNode(pRuntimeLookup->helper, TYP_I_IMPL, helperArgs);
return gtNewRuntimeLookupHelperCallNode(pRuntimeLookup, ctxTree, compileTimeHandle);
}

// Slot pointer
Expand Down
142 changes: 54 additions & 88 deletions src/coreclr/src/jit/morph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7259,7 +7259,7 @@ GenTree* Compiler::fgMorphPotentialTailCall(GenTreeCall* call)
}

// On x86 we have a faster mechanism than the general one which we use
// in almost all cases.
// in almost all cases. See fgCanTailCallViaJitHelper for more information.
if (fgCanTailCallViaJitHelper())
{
tailCallViaJitHelper = true;
Expand Down Expand Up @@ -7912,6 +7912,16 @@ GenTree* Compiler::fgCreateCallDispatcherAndGetResult(GenTreeCall* orig
return comma;
}

//------------------------------------------------------------------------
// getMethodPointerTree: get a method pointer tree
//
// Arguments:
// pResolvedToken - resolved token of the call
// pCallInfo - the call info of the call
//
// Return Value:
// A node representing the method pointer
//
GenTree* Compiler::getMethodPointerTree(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_CALL_INFO* pCallInfo)
{
switch (pCallInfo->kind)
Expand All @@ -7926,6 +7936,18 @@ GenTree* Compiler::getMethodPointerTree(CORINFO_RESOLVED_TOKEN* pResolvedToken,
}
}

//------------------------------------------------------------------------
// getLookupTree: get a lookup tree
//
// Arguments:
// pResolvedToken - resolved token of the call
// pLookup - the lookup to get the tree for
// handleFlags - flags to set on the result node
// compileTimeHandle - compile-time handle corresponding to the lookup
//
// Return Value:
// A node representing the lookup tree
//
GenTree* Compiler::getLookupTree(CORINFO_RESOLVED_TOKEN* pResolvedToken,
CORINFO_LOOKUP* pLookup,
unsigned handleFlags,
Expand Down Expand Up @@ -7955,24 +7977,39 @@ GenTree* Compiler::getLookupTree(CORINFO_RESOLVED_TOKEN* pResolvedToken,
return getRuntimeLookupTree(pResolvedToken, pLookup, compileTimeHandle);
}

//------------------------------------------------------------------------
// getRuntimeLookupTree: get a tree for a runtime lookup
//
// Arguments:
// pResolvedToken - resolved token of the call
// pLookup - the lookup to get the tree for
// compileTimeHandle - compile-time handle corresponding to the lookup
//
// Return Value:
// A node representing the runtime lookup tree
//
GenTree* Compiler::getRuntimeLookupTree(CORINFO_RESOLVED_TOKEN* pResolvedToken,
CORINFO_LOOKUP* pLookup,
void* compileTimeHandle)
{
// This method can only be called from the importer instance of the Compiler.
// In other word, it cannot be called by the instance of the Compiler for the inlinee.
assert(!compIsForInlining());

CORINFO_RUNTIME_LOOKUP* pRuntimeLookup = &pLookup->runtimeLookup;
// It's available only via the run-time helper function
if (pRuntimeLookup->indirections == CORINFO_USEHELPER)
{
GenTree* argNode =
gtNewIconEmbHndNode(pRuntimeLookup->signature, nullptr, GTF_ICON_TOKEN_HDL, compileTimeHandle);
GenTreeCall::Use* helperArgs =
gtNewCallArgs(getRuntimeContextTree(pLookup->lookupKind.runtimeLookupKind), argNode);

return gtNewHelperCallNode(pRuntimeLookup->helper, TYP_I_IMPL, helperArgs);
// If pRuntimeLookup->indirections is equal to CORINFO_USEHELPER, it specifies that a run-time helper should be
// used; otherwise, it specifies the number of indirections via pRuntimeLookup->offsets array.
if ((pRuntimeLookup->indirections == CORINFO_USEHELPER) || pRuntimeLookup->testForNull ||
pRuntimeLookup->testForFixup)
{
// If the first condition is true, runtime lookup tree is available only via the run-time helper function.
// TODO-CQ If the second or third condition is true, we are always using the slow path since we can't
// introduce control flow at this point. See impRuntimeLookupToTree for the logic to avoid calling the helper.
// The long-term solution is to introduce a new node representing a runtime lookup, create instances
// of that node both in the importer and here, and expand the node in lower (introducing control flow if
// necessary).
return gtNewRuntimeLookupHelperCallNode(pRuntimeLookup,
getRuntimeContextTree(pLookup->lookupKind.runtimeLookupKind),
compileTimeHandle);
}

GenTree* result = getRuntimeContextTree(pLookup->lookupKind.runtimeLookupKind);
Expand All @@ -7996,7 +8033,7 @@ GenTree* Compiler::getRuntimeLookupTree(CORINFO_RESOLVED_TOKEN* pResolvedToken,
return gtNewLclvNode(temp, lvaGetActualType(temp));
};

// Applied repeated indirections
// Apply repeated indirections
for (WORD i = 0; i < pRuntimeLookup->indirections; i++)
{
GenTree* preInd = nullptr;
Expand All @@ -8023,83 +8060,12 @@ GenTree* Compiler::getRuntimeLookupTree(CORINFO_RESOLVED_TOKEN* pResolvedToken,
}
}

// No null test required
if (!pRuntimeLookup->testForNull)
assert(!pRuntimeLookup->testForNull);
if (pRuntimeLookup->indirections > 0)
{
if (pRuntimeLookup->indirections > 0)
{
result = gtNewOperNode(GT_IND, TYP_I_IMPL, result);
result->gtFlags |= GTF_IND_NONFAULTING;

if (pRuntimeLookup->testForFixup)
{
unsigned slotLclNum = lvaGrabTemp(true DEBUGARG("getRuntimeLookupTree test"));
stmts.Push(gtNewTempAssign(slotLclNum, result));

GenTree* slot = gtNewLclvNode(slotLclNum, TYP_I_IMPL);
// downcast the pointer to a TYP_INT on 64-bit targets
slot = impImplicitIorI4Cast(slot, TYP_INT);
// Use a GT_AND to check for the lowest bit and indirect if it is set
GenTree* test = gtNewOperNode(GT_AND, TYP_INT, slot, gtNewIconNode(1));
GenTree* relop = gtNewOperNode(GT_EQ, TYP_INT, test, gtNewIconNode(0));

// slot = GT_IND(slot - 1)
slot = gtNewLclvNode(slotLclNum, TYP_I_IMPL);
GenTree* add = gtNewOperNode(GT_ADD, TYP_I_IMPL, slot, gtNewIconNode(-1, TYP_I_IMPL));
GenTree* indir = gtNewOperNode(GT_IND, TYP_I_IMPL, add);
indir->gtFlags |= GTF_IND_NONFAULTING;
indir->gtFlags |= GTF_IND_INVARIANT;

slot = gtNewLclvNode(slotLclNum, TYP_I_IMPL);
GenTree* asg = gtNewAssignNode(slot, indir);
GenTree* colon = new (this, GT_COLON) GenTreeColon(TYP_VOID, gtNewNothingNode(), asg);
GenTree* qmark = gtNewQmarkNode(TYP_VOID, relop, colon);
stmts.Push(qmark);

result = gtNewLclvNode(slotLclNum, TYP_I_IMPL);
}
}
}
else
{
assert(pRuntimeLookup->indirections != 0);

// Extract the handle
GenTree* handle = gtNewOperNode(GT_IND, TYP_I_IMPL, result);
handle->gtFlags |= GTF_IND_NONFAULTING;

GenTree* handleCopy = cloneTree(&handle DEBUGARG("getRuntimeLookupTree handle"));

// Call to helper
GenTree* argNode =
gtNewIconEmbHndNode(pRuntimeLookup->signature, nullptr, GTF_ICON_TOKEN_HDL, compileTimeHandle);

GenTreeCall::Use* helperArgs =
gtNewCallArgs(getRuntimeContextTree(pLookup->lookupKind.runtimeLookupKind), argNode);
GenTree* helperCall = gtNewHelperCallNode(pRuntimeLookup->helper, TYP_I_IMPL, helperArgs);

result = helperCall;
//// Check for null and possibly call helper
// GenTree* relop = gtNewOperNode(GT_NE, TYP_INT, handle, gtNewIconNode(0, TYP_I_IMPL));

// GenTree* colon = new (this, GT_COLON) GenTreeColon(TYP_I_IMPL,
// gtNewNothingNode(), // do nothing if nonnull
// helperCall);

// GenTree* qmark = gtNewQmarkNode(TYP_I_IMPL, relop, colon);

// unsigned tmp;
// if (handleCopy->IsLocal())
//{
// tmp = handleCopy->gtLclVarCommon.GetLclNum();
//}
// else
//{
// tmp = lvaGrabTemp(true DEBUGARG("spilling QMark1"));
//}

// stmts.Push(gtNewTempAssign(tmp, qmark));
// result = gtNewLclvNode(tmp, TYP_I_IMPL);
assert(!pRuntimeLookup->testForFixup);
result = gtNewOperNode(GT_IND, TYP_I_IMPL, result);
result->gtFlags |= GTF_IND_NONFAULTING;
}

// Produces GT_COMMA(stmt1, GT_COMMA(stmt2, ... GT_COMMA(stmtN, result)))
Expand Down

0 comments on commit 2f0cd3e

Please sign in to comment.