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