Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Import KEEPALIVE(BOX) as KEEPALIVE(ADDR(TEMP)) #54412

Merged
13 commits merged into from
Sep 3, 2021
4 changes: 4 additions & 0 deletions src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -3056,6 +3056,8 @@ class Compiler

GenTree* gtUnusedValNode(GenTree* expr);

GenTree* gtNewKeepAliveNode(GenTree* op);

GenTreeCast* gtNewCastNode(var_types typ, GenTree* op1, bool fromUnsigned, var_types castType);

GenTreeCast* gtNewCastNodeL(var_types typ, GenTree* op1, bool fromUnsigned, var_types castType);
Expand Down Expand Up @@ -4182,6 +4184,8 @@ class Compiler
CorInfoIntrinsics intrinsicID);
GenTree* impInitializeArrayIntrinsic(CORINFO_SIG_INFO* sig);

GenTree* impKeepAliveIntrinsic(GenTree* objToKeepAlive);

GenTree* impMethodPointer(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_CALL_INFO* pCallInfo);

GenTree* impTransformThis(GenTree* thisPtr,
Expand Down
14 changes: 14 additions & 0 deletions src/coreclr/jit/compiler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1344,6 +1344,20 @@ inline void GenTree::SetOper(genTreeOps oper, ValueNumberUpdate vnUpdate)
}
}

inline GenTree* Compiler::gtNewKeepAliveNode(GenTree* op)
{
GenTree* keepalive = gtNewOperNode(GT_KEEPALIVE, TYP_VOID, op);

// Prevent both reordering and removal. Invalid optimizations of GC.KeepAlive are
// very subtle and hard to observe. Thus we are conservatively marking it with both
// GTF_CALL and GTF_GLOB_REF side-effects even though it may be more than strictly
// necessary. The conservative side-effects are unlikely to have negative impact
// on code quality in this case.
keepalive->gtFlags |= (GTF_CALL | GTF_GLOB_REF);

return keepalive;
}

inline GenTreeCast* Compiler::gtNewCastNode(var_types typ, GenTree* op1, bool fromUnsigned, var_types castType)
{
GenTreeCast* cast = new (this, GT_CAST) GenTreeCast(typ, op1, fromUnsigned, castType);
Expand Down
70 changes: 61 additions & 9 deletions src/coreclr/jit/importer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4532,15 +4532,7 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis,

case NI_System_GC_KeepAlive:
{
retNode = gtNewOperNode(GT_KEEPALIVE, TYP_VOID, impPopStack().val);

// Prevent both reordering and removal. Invalid optimizations of GC.KeepAlive are
// very subtle and hard to observe. Thus we are conservatively marking it with both
// GTF_CALL and GTF_GLOB_REF side-effects even though it may be more than strictly
// necessary. The conservative side-effects are unlikely to have negative impact
// on code quality in this case.
retNode->gtFlags |= (GTF_CALL | GTF_GLOB_REF);

retNode = impKeepAliveIntrinsic(impPopStack().val);
break;
}

Expand Down Expand Up @@ -5277,6 +5269,66 @@ GenTree* Compiler::impArrayAccessIntrinsic(
}
}

//------------------------------------------------------------------------
// impKeepAliveIntrinsic: Import the GC.KeepAlive intrinsic call
//
// Imports the intrinsic as a GT_KEEPALIVE node, and, as an optimization,
// if the object to keep alive is a GT_BOX, removes its side effects and
// uses the address of a local (copied from the box's source if needed)
// as the operand for GT_KEEPALIVE. For the BOX optimization, if the class
// of the box has no GC fields, a GT_NOP is returned.
//
// Arguments:
// objToKeepAlive - the intrinisic call's argument
//
// Return Value:
// The imported GT_KEEPALIVE or GT_NOP - see description.
//
GenTree* Compiler::impKeepAliveIntrinsic(GenTree* objToKeepAlive)
{
assert(objToKeepAlive->TypeIs(TYP_REF));

if (opts.OptimizationEnabled() && objToKeepAlive->IsBoxedValue())
{
CORINFO_CLASS_HANDLE boxedClass = lvaGetDesc(objToKeepAlive->AsBox()->BoxOp()->AsLclVar())->lvClassHnd;
ClassLayout* layout = typGetObjLayout(boxedClass);

if (!layout->HasGCPtr())
{
gtTryRemoveBoxUpstreamEffects(objToKeepAlive, BR_REMOVE_AND_NARROW);
JITDUMP("\nBOX class has no GC fields, KEEPALIVE is a NOP");

return gtNewNothingNode();
}

GenTree* boxSrc = gtTryRemoveBoxUpstreamEffects(objToKeepAlive, BR_REMOVE_BUT_NOT_NARROW);
if (boxSrc != nullptr)
{
unsigned boxTempNum;
if (boxSrc->OperIs(GT_LCL_VAR))
{
boxTempNum = boxSrc->AsLclVarCommon()->GetLclNum();
}
else
{
boxTempNum = lvaGrabTemp(true DEBUGARG("Temp for the box source"));
GenTree* boxTempAsg = gtNewTempAssign(boxTempNum, boxSrc);
Statement* boxAsgStmt = objToKeepAlive->AsBox()->gtCopyStmtWhenInlinedBoxValue;
boxAsgStmt->SetRootNode(boxTempAsg);
}

JITDUMP("\nImporting KEEPALIVE(BOX) as KEEPALIVE(ADDR(LCL_VAR V%02u))", boxTempNum);

GenTree* boxTemp = gtNewLclvNode(boxTempNum, boxSrc->TypeGet());
GenTree* boxTempAddr = gtNewOperNode(GT_ADDR, TYP_BYREF, boxTemp);

return gtNewKeepAliveNode(boxTempAddr);
}
}

return gtNewKeepAliveNode(objToKeepAlive);
}

bool Compiler::verMergeEntryStates(BasicBlock* block, bool* changed)
{
unsigned i;
Expand Down