Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 25 additions & 2 deletions src/coreclr/jit/codegenarmarch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2815,14 +2815,22 @@ void CodeGen::genCodeForCpBlkUnroll(GenTreeBlk* node)
CopyBlockUnrollHelper helper(srcOffset, dstOffset, size);
regNumber srcReg = srcAddrBaseReg;

#ifdef DEBUG
bool isSrcRegAddrAlignmentKnown = false;
bool isDstRegAddrAlignmentKnown = false;
#endif

if (srcLclNum != BAD_VAR_NUM)
{
bool fpBased;
const int baseAddr = compiler->lvaFrameAddress(srcLclNum, &fpBased);

srcReg = fpBased ? REG_FPBASE : REG_SPBASE;

helper.SetSrcOffset(baseAddr + srcOffset);

#ifdef DEBUG
isSrcRegAddrAlignmentKnown = true;
#endif
}

regNumber dstReg = dstAddrBaseReg;
Expand All @@ -2833,8 +2841,11 @@ void CodeGen::genCodeForCpBlkUnroll(GenTreeBlk* node)
const int baseAddr = compiler->lvaFrameAddress(dstLclNum, &fpBased);

dstReg = fpBased ? REG_FPBASE : REG_SPBASE;

helper.SetDstOffset(baseAddr + dstOffset);

#ifdef DEBUG
isDstRegAddrAlignmentKnown = true;
#endif
}

bool canEncodeAllLoads = true;
Expand Down Expand Up @@ -2948,6 +2959,18 @@ void CodeGen::genCodeForCpBlkUnroll(GenTreeBlk* node)
}
#endif

#ifndef JIT32_GCENCODER
if (!node->gtBlkOpGcUnsafe && ((srcOffsetAdjustment != 0) || (dstOffsetAdjustment != 0)))
{
// If node is not already marked as non-interruptible, and if are about to generate code
// that produce GC references in temporary registers not reported, then mark the block
// as non-interruptible.
// Corresponding EnableGC() will be done by the caller of this method.
node->gtBlkOpGcUnsafe = true;
GetEmitter()->emitDisableGC();
}
#endif

if ((srcOffsetAdjustment != 0) && (dstOffsetAdjustment != 0))
{
const regNumber tempReg1 = node->ExtractTempReg(RBM_ALLINT);
Expand Down
10 changes: 1 addition & 9 deletions src/coreclr/jit/lowerarmarch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -440,18 +440,10 @@ void Lowering::LowerBlockStore(GenTreeBlk* blkNode)

if (blkNode->OperIs(GT_STORE_OBJ))
{
if (!blkNode->AsObj()->GetLayout()->HasGCPtr())
if (!blkNode->AsObj()->GetLayout()->HasGCPtr() || (isDstAddrLocal && (size <= copyBlockUnrollLimit)))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like a bug: before, if (isDstAddrLocal && (size <= copyBlockUnrollLimit)), we would set gtBlkOpGcUnsafe=true. Now, we won't unless !isSrcAddrLocal.

So, if both isSrcAddrLocal and isDstAddrLocal are true, we won't disable GC. However, the thing we are copying contains GC pointers in this case, and the GC pointers loaded into temporary registers aren't reported, so we have a GC hole.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's true. I missed that case.

{
blkNode->SetOper(GT_STORE_BLK);
}
else if (isDstAddrLocal && (size <= copyBlockUnrollLimit))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like we don't need the isDstAddrLocal check: why can't we use this code path even if copying with src=heap, dst=heap, or src=stack, dst=heap?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was trying to consolidate the blkNode->SetOper(GT_STORE_BLK) case, but in general, we need to disable GC for following unroll cases:

  • isDstAddrLocal = true (as of today)
  • isDstAddrLocal = false (if dst is on heap)
  • isSrcAddrLocal = false (if src is on heap)
  • isSrcAddrLocal = true (since we want to disable GC regardless if dst is on stack/heap, src state won't matter).

So basically, if we are doing GT_STORE_BLK and unrolling, we need to disable GC. With that said, I think we should disable the GC inside genCodeForCpBlkUnroll() only for cases where we will be doing the adjustments i.e. srcOffsetAdjustment != 0 || dstOffsetAdjustment != 0 to limit it to scenarios that are really affected.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With that being the case, I missed a case for objects that has GC pointers. Fixed in #70053

{
// If the size is small enough to unroll then we need to mark the block as non-interruptible
// to actually allow unrolling. The generated code does not report GC references loaded in the
// temporary register(s) used for copying.
blkNode->SetOper(GT_STORE_BLK);
blkNode->gtBlkOpGcUnsafe = true;
}
}

if (blkNode->OperIs(GT_STORE_OBJ))
Expand Down