Skip to content

Commit 609ef46

Browse files
authored
Fold static readonly struct X = <zero> to a jit-time const, e.g. Guid.Empty (#77354)
1 parent 93d73d1 commit 609ef46

File tree

2 files changed

+53
-5
lines changed

2 files changed

+53
-5
lines changed

src/coreclr/jit/importer.cpp

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4154,6 +4154,8 @@ GenTree* Compiler::impImportStaticReadOnlyField(CORINFO_FIELD_HANDLE field, CORI
41544154
return nullptr;
41554155
}
41564156

4157+
JITDUMP("\nChecking if we can import 'static readonly' as a jit-time constant... ")
4158+
41574159
CORINFO_CLASS_HANDLE fieldClsHnd;
41584160
var_types fieldType = JITtype2varType(info.compCompHnd->getFieldType(field, &fieldClsHnd, ownerCls));
41594161

@@ -4167,20 +4169,64 @@ GenTree* Compiler::impImportStaticReadOnlyField(CORINFO_FIELD_HANDLE field, CORI
41674169
GenTree* cnsValue = impImportCnsTreeFromBuffer(buffer, fieldType);
41684170
if (cnsValue != nullptr)
41694171
{
4172+
JITDUMP("... success! The value is:\n");
4173+
DISPTREE(cnsValue);
41704174
return cnsValue;
41714175
}
41724176
}
41734177
}
41744178
else if (fieldType == TYP_STRUCT)
41754179
{
4180+
unsigned totalSize = info.compCompHnd->getClassSize(fieldClsHnd);
4181+
unsigned fieldsCnt = info.compCompHnd->getClassNumInstanceFields(fieldClsHnd);
41764182

4177-
if (info.compCompHnd->getClassNumInstanceFields(fieldClsHnd) != 1)
4183+
// For large structs we only want to handle "initialized with zero" case
4184+
// e.g. Guid.Empty and decimal.Zero static readonly fields.
4185+
if ((totalSize > TARGET_POINTER_SIZE) || (fieldsCnt != 1))
41784186
{
4179-
// Only single-field structs are supported here to avoid potential regressions where
4180-
// Metadata-driven struct promotion leads to regressions.
4187+
JITDUMP("checking if we can do anything for a large struct ...");
4188+
const int MaxStructSize = 64;
4189+
if ((totalSize == 0) || (totalSize > MaxStructSize))
4190+
{
4191+
// Limit to 64 bytes for better throughput
4192+
JITDUMP("struct is larger than 64 bytes - bail out.");
4193+
return nullptr;
4194+
}
4195+
4196+
uint8_t buffer[MaxStructSize] = {0};
4197+
if (info.compCompHnd->getReadonlyStaticFieldValue(field, buffer, totalSize))
4198+
{
4199+
for (unsigned i = 0; i < totalSize; i++)
4200+
{
4201+
if (buffer[i] != 0)
4202+
{
4203+
// Value is not all zeroes - bail out.
4204+
// Although, We might eventually support that too.
4205+
JITDUMP("value is not all zeros - bail out.");
4206+
return nullptr;
4207+
}
4208+
}
4209+
4210+
JITDUMP("success! Optimizing to ASG(struct, 0).");
4211+
unsigned structTempNum = lvaGrabTemp(true DEBUGARG("folding static ro fld empty struct"));
4212+
lvaSetStruct(structTempNum, fieldClsHnd, false);
4213+
4214+
// realType is either struct or SIMD
4215+
var_types realType = lvaGetRealType(structTempNum);
4216+
GenTreeLclVar* structLcl = gtNewLclvNode(structTempNum, realType);
4217+
impAppendTree(gtNewBlkOpNode(structLcl, gtNewIconNode(0), false, false), CHECK_SPILL_NONE,
4218+
impCurStmtDI);
4219+
4220+
return gtNewLclvNode(structTempNum, realType);
4221+
}
4222+
4223+
JITDUMP("getReadonlyStaticFieldValue returned false - bail out.");
41814224
return nullptr;
41824225
}
41834226

4227+
// Only single-field structs are supported here to avoid potential regressions where
4228+
// Metadata-driven struct promotion leads to regressions.
4229+
41844230
CORINFO_FIELD_HANDLE innerField = info.compCompHnd->getFieldInClass(fieldClsHnd, 0);
41854231
CORINFO_CLASS_HANDLE innerFieldClsHnd;
41864232
var_types fieldVarType =
@@ -4189,15 +4235,16 @@ GenTree* Compiler::impImportStaticReadOnlyField(CORINFO_FIELD_HANDLE field, CORI
41894235
// Technically, we can support frozen gc refs here and maybe floating point in future
41904236
if (!varTypeIsIntegral(fieldVarType))
41914237
{
4238+
JITDUMP("struct has non-primitive fields - bail out.");
41924239
return nullptr;
41934240
}
41944241

4195-
unsigned totalSize = info.compCompHnd->getClassSize(fieldClsHnd);
41964242
unsigned fldOffset = info.compCompHnd->getFieldOffset(innerField);
41974243

4198-
if ((fldOffset != 0) || (totalSize != info.compCompHnd->getClassSize(fieldClsHnd)) || (totalSize == 0))
4244+
if ((fldOffset != 0) || (totalSize != genTypeSize(fieldVarType)) || (totalSize == 0))
41994245
{
42004246
// The field is expected to be of the exact size as the struct with 0 offset
4247+
JITDUMP("struct has complex layout - bail out.");
42014248
return nullptr;
42024249
}
42034250

src/libraries/System.Private.CoreLib/src/System/Guid.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -868,6 +868,7 @@ public override int GetHashCode()
868868

869869
public bool Equals(Guid g) => EqualsCore(this, g);
870870

871+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
871872
private static bool EqualsCore(in Guid left, in Guid right)
872873
{
873874
if (Vector128.IsHardwareAccelerated)

0 commit comments

Comments
 (0)