Skip to content

Commit 653cb87

Browse files
Optimize "new DateTime(<const args>)" via improvements in JIT VN (#81005)
Co-authored-by: SingleAccretion <[email protected]>
1 parent 825323f commit 653cb87

File tree

4 files changed

+77
-29
lines changed

4 files changed

+77
-29
lines changed

src/coreclr/jit/assertionprop.cpp

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3227,13 +3227,10 @@ GenTree* Compiler::optVNConstantPropOnTree(BasicBlock* block, GenTree* tree)
32273227

32283228
if (conValTree != nullptr)
32293229
{
3230-
if (tree->OperIs(GT_LCL_VAR))
3230+
if (!optIsProfitableToSubstitute(tree, block, conValTree))
32313231
{
3232-
if (!optIsProfitableToSubstitute(tree->AsLclVar(), block, conValTree))
3233-
{
3234-
// Not profitable to substitute
3235-
return nullptr;
3236-
}
3232+
// Not profitable to substitute
3233+
return nullptr;
32373234
}
32383235

32393236
// Were able to optimize.
@@ -3259,27 +3256,35 @@ GenTree* Compiler::optVNConstantPropOnTree(BasicBlock* block, GenTree* tree)
32593256
}
32603257

32613258
//------------------------------------------------------------------------------
3262-
// optIsProfitableToSubstitute: Checks if value worth substituting to lcl location
3259+
// optIsProfitableToSubstitute: Checks if value worth substituting to dest
32633260
//
32643261
// Arguments:
3265-
// lcl - lcl to replace with value if profitable
3266-
// lclBlock - Basic block lcl located in
3267-
// value - value we plan to substitute to lcl
3262+
// dest - destination to substitute value to
3263+
// destBlock - Basic block of destination
3264+
// value - value we plan to substitute
32683265
//
32693266
// Returns:
32703267
// False if it's likely not profitable to do substitution, True otherwise
32713268
//
3272-
bool Compiler::optIsProfitableToSubstitute(GenTreeLclVarCommon* lcl, BasicBlock* lclBlock, GenTree* value)
3269+
bool Compiler::optIsProfitableToSubstitute(GenTree* dest, BasicBlock* destBlock, GenTree* value)
32733270
{
3271+
// Giving up on these kinds of handles demonstrated size improvements
3272+
if (value->IsIconHandle(GTF_ICON_STATIC_HDL, GTF_ICON_CLASS_HDL))
3273+
{
3274+
return false;
3275+
}
3276+
32743277
// A simple heuristic: If the constant is defined outside of a loop (not far from its head)
32753278
// and is used inside it - don't propagate.
32763279

32773280
// TODO: Extend on more kinds of trees
3278-
if (!value->OperIs(GT_CNS_VEC, GT_CNS_DBL))
3281+
if (!value->OperIs(GT_CNS_VEC, GT_CNS_DBL) || !dest->OperIs(GT_LCL_VAR))
32793282
{
32803283
return true;
32813284
}
32823285

3286+
const GenTreeLclVar* lcl = dest->AsLclVar();
3287+
32833288
gtPrepareCost(value);
32843289

32853290
if ((value->GetCostEx() > 1) && (value->GetCostSz() > 1))
@@ -3294,11 +3299,11 @@ bool Compiler::optIsProfitableToSubstitute(GenTreeLclVarCommon* lcl, BasicBlock*
32943299
// NOTE: this currently does not take "a float living across a call" case into account
32953300
// where we might end up with spill/restore on ABIs without callee-saved registers
32963301
const weight_t defBlockWeight = defBlock->getBBWeight(this);
3297-
const weight_t lclblockWeight = lclBlock->getBBWeight(this);
3302+
const weight_t lclblockWeight = destBlock->getBBWeight(this);
32983303

32993304
if ((defBlockWeight > 0) && ((lclblockWeight / defBlockWeight) >= BB_LOOP_WEIGHT_SCALE))
33003305
{
3301-
JITDUMP("Constant propagation inside loop " FMT_BB " is not profitable\n", lclBlock->bbNum);
3306+
JITDUMP("Constant propagation inside loop " FMT_BB " is not profitable\n", destBlock->bbNum);
33023307
return false;
33033308
}
33043309
}

src/coreclr/jit/compiler.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7502,7 +7502,7 @@ class Compiler
75027502
GenTree* optConstantAssertionProp(AssertionDsc* curAssertion,
75037503
GenTreeLclVarCommon* tree,
75047504
Statement* stmt DEBUGARG(AssertionIndex index));
7505-
bool optIsProfitableToSubstitute(GenTreeLclVarCommon* lcl, BasicBlock* lclBlock, GenTree* value);
7505+
bool optIsProfitableToSubstitute(GenTree* dest, BasicBlock* destBlock, GenTree* value);
75067506
bool optZeroObjAssertionProp(GenTree* tree, ASSERT_VALARG_TP assertions);
75077507

75087508
// Assertion propagation functions.

src/coreclr/jit/valuenum.cpp

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,7 @@ ValueNumStore::ValueNumStore(Compiler* comp, CompAllocator alloc)
436436
, m_longCnsMap(nullptr)
437437
, m_handleMap(nullptr)
438438
, m_embeddedToCompileTimeHandleMap(alloc)
439+
, m_fieldAddressToFieldSeqMap(alloc)
439440
, m_floatCnsMap(nullptr)
440441
, m_doubleCnsMap(nullptr)
441442
, m_byrefCnsMap(nullptr)
@@ -8254,12 +8255,20 @@ void Compiler::fgValueNumberTreeConst(GenTree* tree)
82548255
case TYP_BOOL:
82558256
if (tree->IsIconHandle())
82568257
{
8257-
const ssize_t embeddedHandle = tree->AsIntCon()->IconValue();
8258-
tree->gtVNPair.SetBoth(vnStore->VNForHandle(embeddedHandle, tree->GetIconHandleFlag()));
8259-
if (tree->GetIconHandleFlag() == GTF_ICON_CLASS_HDL)
8258+
const GenTreeIntCon* cns = tree->AsIntCon();
8259+
const GenTreeFlags handleFlags = tree->GetIconHandleFlag();
8260+
tree->gtVNPair.SetBoth(vnStore->VNForHandle(cns->IconValue(), handleFlags));
8261+
if (handleFlags == GTF_ICON_CLASS_HDL)
82608262
{
8261-
const ssize_t compileTimeHandle = tree->AsIntCon()->gtCompileTimeHandle;
8262-
vnStore->AddToEmbeddedHandleMap(embeddedHandle, compileTimeHandle);
8263+
vnStore->AddToEmbeddedHandleMap(cns->IconValue(), cns->gtCompileTimeHandle);
8264+
}
8265+
else if ((handleFlags == GTF_ICON_STATIC_HDL) && (cns->gtFieldSeq != nullptr) &&
8266+
(cns->gtFieldSeq->GetKind() == FieldSeq::FieldKind::SimpleStaticKnownAddress))
8267+
{
8268+
assert(cns->IconValue() == cns->gtFieldSeq->GetOffset());
8269+
8270+
// For now we're interested only in SimpleStaticKnownAddress
8271+
vnStore->AddToFieldAddressToFieldSeqMap(cns->gtVNPair.GetLiberal(), cns->gtFieldSeq);
82638272
}
82648273
}
82658274
else if ((typ == TYP_LONG) || (typ == TYP_ULONG))
@@ -8570,13 +8579,13 @@ static bool GetStaticFieldSeqAndAddress(ValueNumStore* vnStore, GenTree* tree, s
85708579
ValueNum op1vn = op1->gtVNPair.GetLiberal();
85718580
ValueNum op2vn = op2->gtVNPair.GetLiberal();
85728581

8573-
if (!op1->IsIconHandle(GTF_ICON_STATIC_HDL) && op1->gtVNPair.BothEqual() && vnStore->IsVNConstant(op1vn) &&
8582+
if (op1->gtVNPair.BothEqual() && vnStore->IsVNConstant(op1vn) && !vnStore->IsVNHandle(op1vn) &&
85748583
varTypeIsIntegral(vnStore->TypeOfVN(op1vn)))
85758584
{
85768585
val += vnStore->CoercedConstantValue<ssize_t>(op1vn);
85778586
tree = op2;
85788587
}
8579-
else if (!op2->IsIconHandle(GTF_ICON_STATIC_HDL) && op2->gtVNPair.BothEqual() && vnStore->IsVNConstant(op2vn) &&
8588+
else if (op2->gtVNPair.BothEqual() && vnStore->IsVNConstant(op2vn) && !vnStore->IsVNHandle(op2vn) &&
85808589
varTypeIsIntegral(vnStore->TypeOfVN(op2vn)))
85818590
{
85828591
val += vnStore->CoercedConstantValue<ssize_t>(op2vn);
@@ -8590,12 +8599,20 @@ static bool GetStaticFieldSeqAndAddress(ValueNumStore* vnStore, GenTree* tree, s
85908599
}
85918600

85928601
// Base address is expected to be static field's address
8593-
if ((tree->IsCnsIntOrI()) && (tree->AsIntCon()->gtFieldSeq != nullptr) &&
8594-
(tree->AsIntCon()->gtFieldSeq->GetKind() == FieldSeq::FieldKind::SimpleStaticKnownAddress))
8602+
ValueNum treeVN = tree->gtVNPair.GetLiberal();
8603+
if (tree->gtVNPair.BothEqual() && vnStore->IsVNHandle(treeVN) &&
8604+
(vnStore->GetHandleFlags(treeVN) == GTF_ICON_STATIC_HDL))
85958605
{
8596-
*pFseq = tree->AsIntCon()->gtFieldSeq;
8597-
*byteOffset = tree->AsIntCon()->IconValue() + val - tree->AsIntCon()->gtFieldSeq->GetOffset();
8598-
return true;
8606+
FieldSeq* fldSeq = vnStore->GetFieldSeqFromAddress(treeVN);
8607+
if (fldSeq != nullptr)
8608+
{
8609+
assert(fldSeq->GetKind() == FieldSeq::FieldKind::SimpleStaticKnownAddress);
8610+
assert(fldSeq->GetOffset() == vnStore->CoercedConstantValue<ssize_t>(treeVN));
8611+
8612+
*pFseq = fldSeq;
8613+
*byteOffset = val;
8614+
return true;
8615+
}
85998616
}
86008617
return false;
86018618
}
@@ -9769,6 +9786,13 @@ ValueNum ValueNumStore::VNForCast(ValueNum srcVN,
97699786
bool srcIsUnsigned, /* = false */
97709787
bool hasOverflowCheck) /* = false */
97719788
{
9789+
9790+
if ((castFromType == TYP_I_IMPL) && (castToType == TYP_BYREF) && IsVNHandle(srcVN))
9791+
{
9792+
// Omit cast for (h)CNS_INT [TYP_I_IMPL -> TYP_BYREF]
9793+
return srcVN;
9794+
}
9795+
97729796
// The resulting type after performing the cast is always widened to a supported IL stack size
97739797
var_types resultType = genActualType(castToType);
97749798

@@ -9808,8 +9832,9 @@ ValueNumPair ValueNumStore::VNPairForCast(ValueNumPair srcVNPair,
98089832
bool srcIsUnsigned, /* = false */
98099833
bool hasOverflowCheck) /* = false */
98109834
{
9811-
ValueNum srcLibVN = srcVNPair.GetLiberal();
9812-
ValueNum srcConVN = srcVNPair.GetConservative();
9835+
ValueNum srcLibVN = srcVNPair.GetLiberal();
9836+
ValueNum srcConVN = srcVNPair.GetConservative();
9837+
98139838
ValueNum castLibVN = VNForCast(srcLibVN, castToType, castFromType, srcIsUnsigned, hasOverflowCheck);
98149839
ValueNum castConVN;
98159840

src/coreclr/jit/valuenum.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,21 @@ class ValueNumStore
463463
m_embeddedToCompileTimeHandleMap.AddOrUpdate(embeddedHandle, compileTimeHandle);
464464
}
465465

466+
void AddToFieldAddressToFieldSeqMap(ValueNum fldAddr, FieldSeq* fldSeq)
467+
{
468+
m_fieldAddressToFieldSeqMap.AddOrUpdate(fldAddr, fldSeq);
469+
}
470+
471+
FieldSeq* GetFieldSeqFromAddress(ValueNum fldAddr)
472+
{
473+
FieldSeq* fldSeq;
474+
if (m_fieldAddressToFieldSeqMap.TryGetValue(fldAddr, &fldSeq))
475+
{
476+
return fldSeq;
477+
}
478+
return nullptr;
479+
}
480+
466481
// And the single constant for an object reference type.
467482
static ValueNum VNForNull()
468483
{
@@ -1423,6 +1438,9 @@ class ValueNumStore
14231438
typedef SmallHashTable<ssize_t, ssize_t> EmbeddedToCompileTimeHandleMap;
14241439
EmbeddedToCompileTimeHandleMap m_embeddedToCompileTimeHandleMap;
14251440

1441+
typedef SmallHashTable<ValueNum, FieldSeq*> FieldAddressToFieldSeqMap;
1442+
FieldAddressToFieldSeqMap m_fieldAddressToFieldSeqMap;
1443+
14261444
struct LargePrimitiveKeyFuncsFloat : public JitLargePrimitiveKeyFuncs<float>
14271445
{
14281446
static bool Equals(float x, float y)

0 commit comments

Comments
 (0)