@@ -10600,8 +10600,20 @@ GenTree* Compiler::fgMorphCopyBlock(GenTree* tree)
1060010600 // If we passed the above checks, then we will check these two
1060110601 if (!requiresCopyBlock)
1060210602 {
10603+ // It is not always profitable to do field by field init for structs that are allocated to memory.
10604+ // A struct with 8 bool fields will require 8 moves instead of one if we do this transformation.
10605+ // A simple heuristic when field by field copy is prefered:
10606+ // - if fields can be enregistered;
10607+ // - if the struct has GCPtrs (block copy would be done via helper that is expensive);
10608+ // - if the struct has only one field.
10609+ bool dstFldIsProfitable =
10610+ ((destLclVar != nullptr) &&
10611+ (!destLclVar->lvDoNotEnregister || destLclVar->HasGCPtr() || (destLclVar->lvFieldCnt == 1)));
10612+ bool srcFldIsProfitable =
10613+ ((srcLclVar != nullptr) &&
10614+ (!srcLclVar->lvDoNotEnregister || srcLclVar->HasGCPtr() || (srcLclVar->lvFieldCnt == 1)));
1060310615 // Are both dest and src promoted structs?
10604- if (destDoFldAsg && srcDoFldAsg)
10616+ if (destDoFldAsg && srcDoFldAsg && (dstFldIsProfitable || srcFldIsProfitable) )
1060510617 {
1060610618 // Both structs should be of the same type, or have the same number of fields of the same type.
1060710619 // If not we will use a copy block.
@@ -10633,13 +10645,7 @@ GenTree* Compiler::fgMorphCopyBlock(GenTree* tree)
1063310645 }
1063410646 }
1063510647 }
10636- // Are neither dest or src promoted structs?
10637- else if (!destDoFldAsg && !srcDoFldAsg)
10638- {
10639- requiresCopyBlock = true; // Leave as a CopyBlock
10640- JITDUMP(" with no promoted structs");
10641- }
10642- else if (destDoFldAsg)
10648+ else if (destDoFldAsg && dstFldIsProfitable)
1064310649 {
1064410650 // Match the following kinds of trees:
1064510651 // fgMorphTree BB01, stmt 9 (before)
@@ -10683,9 +10689,8 @@ GenTree* Compiler::fgMorphCopyBlock(GenTree* tree)
1068310689 }
1068410690 }
1068510691 }
10686- else
10692+ else if (srcDoFldAsg && srcFldIsProfitable)
1068710693 {
10688- assert(srcDoFldAsg);
1068910694 // Check for the symmetric case (which happens for the _pointer field of promoted spans):
1069010695 //
1069110696 // [000240] -----+------ /--* lclVar struct(P) V18 tmp9
@@ -10707,6 +10712,13 @@ GenTree* Compiler::fgMorphCopyBlock(GenTree* tree)
1070710712 }
1070810713 }
1070910714 }
10715+ // Are neither dest or src promoted structs?
10716+ else
10717+ {
10718+ assert(!(destDoFldAsg && dstFldIsProfitable) && !(srcDoFldAsg && srcFldIsProfitable));
10719+ requiresCopyBlock = true; // Leave as a CopyBlock
10720+ JITDUMP(" with no promoted structs");
10721+ }
1071010722 }
1071110723
1071210724 // If we require a copy block the set both of the field assign bools to false
0 commit comments