@@ -8212,6 +8212,117 @@ void Lowering::ContainCheckBitCast(GenTree* node)
8212
8212
}
8213
8213
}
8214
8214
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
+
8215
8326
// ------------------------------------------------------------------------
8216
8327
// LowerBlockStoreAsHelperCall: Lower a block store node as a memset/memcpy call
8217
8328
//
0 commit comments