Skip to content

Commit 858f0af

Browse files
committed
Measure last use struct copies
1 parent e4d115a commit 858f0af

File tree

4 files changed

+76
-0
lines changed

4 files changed

+76
-0
lines changed

src/coreclr/jit/codegenxarch.cpp

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5441,6 +5441,8 @@ bool CodeGen::genEmitOptimizedGCWriteBarrier(GCInfo::WriteBarrierForm writeBarri
54415441
#endif // !defined(TARGET_X86) || !NOGC_WRITE_BARRIERS
54425442
}
54435443

5444+
int s_numUnnecessaryLastUseStructCopies;
5445+
54445446
// Produce code for a GT_CALL node
54455447
void CodeGen::genCall(GenTreeCall* call)
54465448
{
@@ -5518,6 +5520,73 @@ void CodeGen::genCall(GenTreeCall* call)
55185520
}
55195521
}
55205522

5523+
for (CallArg& arg : call->gtArgs.Args())
5524+
{
5525+
assert((arg.GetEarlyNode() == nullptr) != (arg.GetLateNode() == nullptr));
5526+
if (!arg.AbiInfo.PassedByRef)
5527+
continue;
5528+
5529+
GenTree* putArg = arg.GetNode();
5530+
GenTree* arg = putArg->gtGetOp1();
5531+
if (!arg->OperIs(GT_LCL_VAR_ADDR))
5532+
continue;
5533+
5534+
unsigned lclNum = arg->AsLclVarCommon()->GetLclNum();
5535+
if ((arg->gtFlags & GTF_VAR_DEATH) != 0)
5536+
continue;
5537+
5538+
GenTree* curNode = arg;
5539+
do
5540+
{
5541+
curNode = curNode->gtPrev;
5542+
5543+
GenTree* storeData = nullptr;
5544+
if (curNode->OperIsStoreBlk() && curNode->AsIndir()->Addr()->OperIsLocalAddr())
5545+
{
5546+
GenTreeLclVarCommon* addr = curNode->AsIndir()->Addr()->AsLclVarCommon();
5547+
if (addr->AsLclVarCommon()->GetLclNum() == lclNum && addr->AsLclVarCommon()->GetLclOffs() == 0)
5548+
storeData = curNode->AsIndir()->Data();
5549+
}
5550+
else if (curNode->OperIsLocalStore())
5551+
{
5552+
GenTreeLclVarCommon* addr = curNode->AsLclVarCommon();
5553+
if (addr->GetLclNum() == lclNum && addr->GetLclOffs() == 0)
5554+
storeData = curNode->AsLclVarCommon()->Data();
5555+
}
5556+
else
5557+
{
5558+
assert(!curNode->OperIsLocal() || curNode->AsLclVarCommon()->GetLclNum() != lclNum);
5559+
}
5560+
5561+
if (storeData != nullptr)
5562+
{
5563+
GenTreeLclVarCommon* srcLcl = nullptr;
5564+
if (storeData->OperIsIndir() && storeData->AsIndir()->Addr()->OperIsLocal())
5565+
{
5566+
GenTreeLclVarCommon* lcl = storeData->AsIndir()->Addr()->AsLclVarCommon();
5567+
if (compiler->lvaGetDesc(lcl)->lvIsImplicitByRef && !compiler->lvaGetDesc(lcl)->lvImplicitByRefAddrExposed)
5568+
srcLcl = lcl;
5569+
}
5570+
else if (storeData->OperIsLocal())
5571+
{
5572+
GenTreeLclVarCommon* lcl = storeData->AsLclVarCommon();
5573+
if (!compiler->lvaGetDesc(lcl)->IsAddressExposed())
5574+
srcLcl = lcl;
5575+
}
5576+
5577+
if (srcLcl != nullptr)
5578+
{
5579+
if ((compiler->lvaGetPromotionType(srcLcl->GetLclNum()) != Compiler::PROMOTION_TYPE_INDEPENDENT) && (srcLcl->gtFlags & GTF_VAR_DEATH) != 0)
5580+
{
5581+
s_numUnnecessaryLastUseStructCopies++;
5582+
}
5583+
}
5584+
5585+
break;
5586+
}
5587+
} while (curNode != LIR::AsRange(compiler->compCurBB).FirstNode());
5588+
}
5589+
55215590
#if defined(TARGET_X86) || defined(UNIX_AMD64_ABI)
55225591
// The call will pop its arguments.
55235592
// for each putarg_stk:

src/coreclr/jit/compiler.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1333,6 +1333,8 @@ void Compiler::compStartup()
13331333
* One time finalization code
13341334
*/
13351335

1336+
extern int s_numUnnecessaryLastUseStructCopies;
1337+
13361338
/* static */
13371339
void Compiler::compShutdown()
13381340
{
@@ -1490,6 +1492,8 @@ void Compiler::compShutdown()
14901492

14911493
#endif // COUNT_AST_OPERS
14921494

1495+
fprintf(fout, "Number of unnecessary struct copies: %d\n", s_numUnnecessaryLastUseStructCopies);
1496+
14931497
#if DISPLAY_SIZES
14941498

14951499
if (grossVMsize && grossNCsize)

src/coreclr/jit/compiler.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,7 @@ class LclVarDsc
461461

462462
unsigned char lvMustInit : 1; // must be initialized
463463

464+
bool lvImplicitByRefAddrExposed : 1;
464465
private:
465466
bool m_addrExposed : 1; // The address of this variable is "exposed" -- passed as an argument, stored in a
466467
// global location, etc.

src/coreclr/jit/morph.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16666,6 +16666,8 @@ PhaseStatus Compiler::fgRetypeImplicitByRefArgs()
1666616666
// Since the parameter in this position is really a pointer, its type is TYP_BYREF.
1666716667
varDsc->lvType = TYP_BYREF;
1666816668

16669+
// 1 if the value of an implicit byref variable is exposed.
16670+
varDsc->lvImplicitByRefAddrExposed = varDsc->IsAddressExposed();
1666916671
// The struct parameter may have had its address taken, but the pointer parameter
1667016672
// cannot -- any uses of the struct parameter's address are uses of the pointer
1667116673
// parameter's value, and there's no way for the MSIL to reference the pointer

0 commit comments

Comments
 (0)