Skip to content

Commit 278081f

Browse files
EgorBomichaelgsharp
authored andcommitted
JIT: Bulk copy of byrefs (dotnet#101761)
1 parent 0212dc4 commit 278081f

File tree

25 files changed

+175
-30
lines changed

25 files changed

+175
-30
lines changed

src/coreclr/inc/corinfo.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -496,7 +496,7 @@ enum CorInfoHelpFunc
496496
CORINFO_HELP_ASSIGN_REF_ENSURE_NONHEAP, // Do the store, and ensure that the target was not in the heap.
497497

498498
CORINFO_HELP_ASSIGN_BYREF,
499-
CORINFO_HELP_ASSIGN_STRUCT,
499+
CORINFO_HELP_BULK_WRITEBARRIER,
500500

501501

502502
/* Accessing fields */

src/coreclr/inc/jiteeversionguid.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,11 @@ typedef const GUID *LPCGUID;
4343
#define GUID_DEFINED
4444
#endif // !GUID_DEFINED
4545

46-
constexpr GUID JITEEVersionIdentifier = { /* 32d71f8e-c1f5-41cb-88cc-4e8504cabf40 */
47-
0x32d71f8e,
48-
0xc1f5,
49-
0x41cb,
50-
{0x88, 0xcc, 0x4e, 0x85, 0x04, 0xca, 0xbf, 0x40}
46+
constexpr GUID JITEEVersionIdentifier = { /* bd8c41d4-8531-49c1-a600-0ae9bfe05de1 */
47+
0xbd8c41d4,
48+
0x8531,
49+
0x49c1,
50+
{0xa6, 0x00, 0x0a, 0xe9, 0xbf, 0xe0, 0x5d, 0xe1}
5151
};
5252

5353
//////////////////////////////////////////////////////////////////////////////////////////////////////////

src/coreclr/inc/jithelpers.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,7 @@
153153
JITHELPER(CORINFO_HELP_ASSIGN_REF_ENSURE_NONHEAP, JIT_WriteBarrierEnsureNonHeapTarget,CORINFO_HELP_SIG_REG_ONLY)
154154

155155
DYNAMICJITHELPER(CORINFO_HELP_ASSIGN_BYREF, JIT_ByRefWriteBarrier,CORINFO_HELP_SIG_NO_ALIGN_STUB)
156-
157-
JITHELPER(CORINFO_HELP_ASSIGN_STRUCT, JIT_StructWriteBarrier,CORINFO_HELP_SIG_4_STACK)
156+
DYNAMICJITHELPER(CORINFO_HELP_BULK_WRITEBARRIER, NULL, CORINFO_HELP_SIG_REG_ONLY)
158157

159158
// Accessing fields
160159
JITHELPER(CORINFO_HELP_GETFIELD8, JIT_GetField8,CORINFO_HELP_SIG_REG_ONLY)

src/coreclr/inc/readytorun.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
// If you update this, ensure you run `git grep MINIMUM_READYTORUN_MAJOR_VERSION`
2121
// and handle pending work.
2222
#define READYTORUN_MAJOR_VERSION 0x0009
23-
#define READYTORUN_MINOR_VERSION 0x0002
23+
#define READYTORUN_MINOR_VERSION 0x0003
2424

2525
#define MINIMUM_READYTORUN_MAJOR_VERSION 0x009
2626

@@ -34,6 +34,7 @@
3434
// R2R Version 9.0 adds support for the Vector512 type
3535
// R2R Version 9.1 adds new helpers to allocate objects on frozen segments
3636
// R2R Version 9.2 adds MemZero and NativeMemSet helpers
37+
// R2R Version 9.3 adds BulkWriteBarrier helper
3738

3839

3940
struct READYTORUN_CORE_HEADER
@@ -321,6 +322,7 @@ enum ReadyToRunHelper
321322
READYTORUN_HELPER_WriteBarrier = 0x30,
322323
READYTORUN_HELPER_CheckedWriteBarrier = 0x31,
323324
READYTORUN_HELPER_ByRefWriteBarrier = 0x32,
325+
READYTORUN_HELPER_BulkWriteBarrier = 0x33,
324326

325327
// Array helpers
326328
READYTORUN_HELPER_Stelem_Ref = 0x38,

src/coreclr/inc/readytorunhelpers.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ HELPER(READYTORUN_HELPER_ThrowDivZero, CORINFO_HELP_THROWDIVZERO,
2424
HELPER(READYTORUN_HELPER_WriteBarrier, CORINFO_HELP_ASSIGN_REF, )
2525
HELPER(READYTORUN_HELPER_CheckedWriteBarrier, CORINFO_HELP_CHECKED_ASSIGN_REF, )
2626
HELPER(READYTORUN_HELPER_ByRefWriteBarrier, CORINFO_HELP_ASSIGN_BYREF, )
27+
HELPER(READYTORUN_HELPER_BulkWriteBarrier, CORINFO_HELP_BULK_WRITEBARRIER, )
2728

2829
HELPER(READYTORUN_HELPER_Stelem_Ref, CORINFO_HELP_ARRADDR_ST, )
2930
HELPER(READYTORUN_HELPER_Ldelema_Ref, CORINFO_HELP_LDELEMA_REF, )

src/coreclr/jit/codegencommon.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1772,7 +1772,7 @@ void CodeGen::genGenerateCode(void** codePtr, uint32_t* nativeSizeOfCode)
17721772
if (genWriteBarrierUsed && JitConfig.EnableExtraSuperPmiQueries() && !compiler->opts.IsReadyToRun())
17731773
{
17741774
void* ignored;
1775-
for (int i = CORINFO_HELP_ASSIGN_REF; i <= CORINFO_HELP_ASSIGN_STRUCT; i++)
1775+
for (int i = CORINFO_HELP_ASSIGN_REF; i <= CORINFO_HELP_BULK_WRITEBARRIER; i++)
17761776
{
17771777
compiler->compGetHelperFtn((CorInfoHelpFunc)i, &ignored);
17781778
}

src/coreclr/jit/lower.cpp

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8212,6 +8212,117 @@ void Lowering::ContainCheckBitCast(GenTree* node)
82128212
}
82138213
}
82148214

8215+
//------------------------------------------------------------------------
8216+
// TryLowerBlockStoreAsGcBulkCopyCall: Lower a block store node as a CORINFO_HELP_BULK_WRITEBARRIER call
8217+
//
8218+
// Arguments:
8219+
// blkNode - The block store node to lower
8220+
//
8221+
bool Lowering::TryLowerBlockStoreAsGcBulkCopyCall(GenTreeBlk* blk)
8222+
{
8223+
if (comp->opts.OptimizationDisabled())
8224+
{
8225+
return false;
8226+
}
8227+
8228+
// Replace STORE_BLK (struct copy) with CORINFO_HELP_BULK_WRITEBARRIER which performs
8229+
// bulk copy for byrefs.
8230+
const unsigned bulkCopyThreshold = 4;
8231+
if (!blk->OperIs(GT_STORE_BLK) || blk->OperIsInitBlkOp() || blk->IsVolatile() ||
8232+
(blk->GetLayout()->GetGCPtrCount() < bulkCopyThreshold))
8233+
{
8234+
return false;
8235+
}
8236+
8237+
GenTree* dest = blk->Addr();
8238+
GenTree* data = blk->Data();
8239+
8240+
if (data->OperIs(GT_IND))
8241+
{
8242+
if (data->AsIndir()->IsVolatile())
8243+
{
8244+
return false;
8245+
}
8246+
8247+
// Drop GT_IND nodes
8248+
BlockRange().Remove(data);
8249+
data = data->AsIndir()->Addr();
8250+
}
8251+
else
8252+
{
8253+
assert(data->OperIs(GT_LCL_VAR, GT_LCL_FLD));
8254+
8255+
// Convert local to LCL_ADDR
8256+
unsigned lclOffset = data->AsLclVarCommon()->GetLclOffs();
8257+
data->ChangeOper(GT_LCL_ADDR);
8258+
data->ChangeType(TYP_I_IMPL);
8259+
data->AsLclFld()->SetLclOffs(lclOffset);
8260+
data->ClearContained();
8261+
}
8262+
8263+
// Size is a constant
8264+
GenTreeIntCon* size = comp->gtNewIconNode((ssize_t)blk->GetLayout()->GetSize(), TYP_I_IMPL);
8265+
BlockRange().InsertBefore(data, size);
8266+
8267+
// A hacky way to safely call fgMorphTree in Lower
8268+
GenTree* destPlaceholder = comp->gtNewZeroConNode(dest->TypeGet());
8269+
GenTree* dataPlaceholder = comp->gtNewZeroConNode(genActualType(data));
8270+
GenTree* sizePlaceholder = comp->gtNewZeroConNode(genActualType(size));
8271+
8272+
GenTreeCall* call = comp->gtNewHelperCallNode(CORINFO_HELP_BULK_WRITEBARRIER, TYP_VOID, destPlaceholder,
8273+
dataPlaceholder, sizePlaceholder);
8274+
comp->fgMorphArgs(call);
8275+
8276+
LIR::Range range = LIR::SeqTree(comp, call);
8277+
GenTree* rangeStart = range.FirstNode();
8278+
GenTree* rangeEnd = range.LastNode();
8279+
8280+
BlockRange().InsertBefore(blk, std::move(range));
8281+
blk->gtBashToNOP();
8282+
8283+
LIR::Use destUse;
8284+
LIR::Use sizeUse;
8285+
BlockRange().TryGetUse(destPlaceholder, &destUse);
8286+
BlockRange().TryGetUse(sizePlaceholder, &sizeUse);
8287+
destUse.ReplaceWith(dest);
8288+
sizeUse.ReplaceWith(size);
8289+
destPlaceholder->SetUnusedValue();
8290+
sizePlaceholder->SetUnusedValue();
8291+
8292+
LIR::Use dataUse;
8293+
BlockRange().TryGetUse(dataPlaceholder, &dataUse);
8294+
dataUse.ReplaceWith(data);
8295+
dataPlaceholder->SetUnusedValue();
8296+
8297+
LowerRange(rangeStart, rangeEnd);
8298+
8299+
// Finally move all GT_PUTARG_* nodes
8300+
// Re-use the existing logic for CFG call args here
8301+
MoveCFGCallArgs(call);
8302+
8303+
BlockRange().Remove(destPlaceholder);
8304+
BlockRange().Remove(sizePlaceholder);
8305+
BlockRange().Remove(dataPlaceholder);
8306+
8307+
// Add implicit nullchecks for dest and data if needed:
8308+
//
8309+
auto wrapWithNullcheck = [&](GenTree* node) {
8310+
if (comp->fgAddrCouldBeNull(node))
8311+
{
8312+
LIR::Use nodeUse;
8313+
BlockRange().TryGetUse(node, &nodeUse);
8314+
GenTree* nodeClone = comp->gtNewLclvNode(nodeUse.ReplaceWithLclVar(comp), genActualType(node));
8315+
GenTree* nullcheck = comp->gtNewNullCheck(nodeClone, comp->compCurBB);
8316+
BlockRange().InsertAfter(nodeUse.Def(), nodeClone, nullcheck);
8317+
LowerNode(nullcheck);
8318+
}
8319+
};
8320+
wrapWithNullcheck(dest);
8321+
wrapWithNullcheck(data);
8322+
8323+
return true;
8324+
}
8325+
82158326
//------------------------------------------------------------------------
82168327
// LowerBlockStoreAsHelperCall: Lower a block store node as a memset/memcpy call
82178328
//

src/coreclr/jit/lower.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,7 @@ class Lowering final : public Phase
363363
void LowerBlockStore(GenTreeBlk* blkNode);
364364
void LowerBlockStoreCommon(GenTreeBlk* blkNode);
365365
void LowerBlockStoreAsHelperCall(GenTreeBlk* blkNode);
366+
bool TryLowerBlockStoreAsGcBulkCopyCall(GenTreeBlk* blkNode);
366367
void LowerLclHeap(GenTree* node);
367368
void ContainBlockStoreAddress(GenTreeBlk* blkNode, unsigned size, GenTree* addr, GenTree* addrParent);
368369
void LowerPutArgStkOrSplit(GenTreePutArgStk* putArgNode);

src/coreclr/jit/lowerarmarch.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -737,6 +737,12 @@ void Lowering::LowerBlockStore(GenTreeBlk* blkNode)
737737

738738
if (doCpObj)
739739
{
740+
// Try to use bulk copy helper
741+
if (TryLowerBlockStoreAsGcBulkCopyCall(blkNode))
742+
{
743+
return;
744+
}
745+
740746
assert((dstAddr->TypeGet() == TYP_BYREF) || (dstAddr->TypeGet() == TYP_I_IMPL));
741747
blkNode->gtBlkOpKind = GenTreeBlk::BlkOpKindCpObjUnroll;
742748
}

src/coreclr/jit/lowerloongarch64.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,12 @@ void Lowering::LowerBlockStore(GenTreeBlk* blkNode)
370370
// CopyObj or CopyBlk
371371
if (doCpObj)
372372
{
373+
// Try to use bulk copy helper
374+
if (TryLowerBlockStoreAsGcBulkCopyCall(blkNode))
375+
{
376+
return;
377+
}
378+
373379
assert((dstAddr->TypeGet() == TYP_BYREF) || (dstAddr->TypeGet() == TYP_I_IMPL));
374380
blkNode->gtBlkOpKind = GenTreeBlk::BlkOpKindCpObjUnroll;
375381
}

0 commit comments

Comments
 (0)