@@ -2663,6 +2663,60 @@ AssertionIndex Compiler::optAssertionIsSubtype(GenTree* tree, GenTree* methodTab
2663
2663
return NO_ASSERTION_INDEX;
2664
2664
}
2665
2665
2666
+ // ------------------------------------------------------------------------------
2667
+ // optVNStrengthReductionOnTree:
2668
+ //
2669
+ // Arguments:
2670
+ // block - The block containing the tree.
2671
+ // parent - The parent node of the tree.
2672
+ // tree - The tree node
2673
+ //
2674
+ // Return Value:
2675
+ // Returns a new tree or nullptr if nothing is changed.
2676
+ //
2677
+ GenTree* Compiler::optVNStrengthReductionOnTree (BasicBlock* block, GenTree* parent, GenTree* tree)
2678
+ {
2679
+ if (tree->IsHelperCall ())
2680
+ {
2681
+ GenTreeCall* call = tree->AsCall ();
2682
+ switch (call->GetHelperNum ())
2683
+ {
2684
+ // Fold "cast(cast(obj, cls), cls)" to "cast(obj, cls)"
2685
+ case CORINFO_HELP_CHKCASTARRAY:
2686
+ case CORINFO_HELP_CHKCASTANY:
2687
+ case CORINFO_HELP_CHKCASTINTERFACE:
2688
+ case CORINFO_HELP_CHKCASTCLASS:
2689
+ case CORINFO_HELP_ISINSTANCEOFARRAY:
2690
+ case CORINFO_HELP_ISINSTANCEOFCLASS:
2691
+ case CORINFO_HELP_ISINSTANCEOFANY:
2692
+ case CORINFO_HELP_ISINSTANCEOFINTERFACE:
2693
+ {
2694
+ GenTree* clsArg = call->gtArgs .GetUserArgByIndex (0 )->GetNode ();
2695
+ GenTree* objArg = call->gtArgs .GetUserArgByIndex (1 )->GetNode ();
2696
+ ValueNum clsArgVN = clsArg->gtVNPair .GetConservative ();
2697
+ ValueNum objArgVN = objArg->gtVNPair .GetConservative ();
2698
+
2699
+ VNFuncApp funcApp;
2700
+ if (vnStore->GetVNFunc (objArgVN, &funcApp) &&
2701
+ ((funcApp.m_func == VNF_CastClass) || (funcApp.m_func == VNF_IsInstanceOf)) &&
2702
+ (funcApp.m_args [0 ] == clsArgVN))
2703
+ {
2704
+ // The outer cast is redundant, remove it and preserve its side effects
2705
+ // We do ignoreRoot here because the actual cast node is proven to never any exceptions
2706
+ // (namely, InvalidCastException).
2707
+ return gtWrapWithSideEffects (objArg, call, GTF_ALL_EFFECT, true );
2708
+ }
2709
+ }
2710
+ break ;
2711
+
2712
+ default :
2713
+ break ;
2714
+ }
2715
+ }
2716
+
2717
+ return nullptr ;
2718
+ }
2719
+
2666
2720
// ------------------------------------------------------------------------------
2667
2721
// optVNConstantPropOnTree: Substitutes tree with an evaluated constant while
2668
2722
// managing side-effects.
@@ -5098,41 +5152,30 @@ GenTree* Compiler::optAssertionProp_Call(ASSERT_VALARG_TP assertions, GenTreeCal
5098
5152
(helper == CORINFO_HELP_CHKCASTCLASS) || (helper == CORINFO_HELP_CHKCASTANY) ||
5099
5153
(helper == CORINFO_HELP_CHKCASTCLASS_SPECIAL))
5100
5154
{
5101
- GenTree* arg1 = call->gtArgs .GetArgByIndex (1 )->GetNode ();
5102
- if (arg1->gtOper != GT_LCL_VAR)
5155
+ GenTree* objArg = call->gtArgs .GetArgByIndex (1 )->GetNode ();
5156
+ GenTree* clsArg = call->gtArgs .GetArgByIndex (0 )->GetNode ();
5157
+
5158
+ if (objArg->gtOper != GT_LCL_VAR)
5103
5159
{
5104
5160
return nullptr ;
5105
5161
}
5106
5162
5107
- GenTree* arg2 = call->gtArgs .GetArgByIndex (0 )->GetNode ();
5108
-
5109
- unsigned index = optAssertionIsSubtype (arg1, arg2, assertions);
5163
+ unsigned index = optAssertionIsSubtype (objArg, clsArg, assertions);
5110
5164
if (index != NO_ASSERTION_INDEX)
5111
5165
{
5112
- #ifdef DEBUG
5113
- if (verbose)
5114
- {
5115
- printf (" \n Did VN based subtype prop for index #%02u in " FMT_BB " :\n " , index, compCurBB->bbNum );
5116
- gtDispTree (call, nullptr , nullptr , true );
5117
- }
5118
- #endif
5119
- GenTree* list = nullptr ;
5120
- gtExtractSideEffList (call, &list, GTF_SIDE_EFFECT, true );
5121
- if (list != nullptr )
5122
- {
5123
- arg1 = gtNewOperNode (GT_COMMA, call->TypeGet (), list, arg1);
5124
- fgSetTreeSeq (arg1);
5125
- }
5166
+ JITDUMP (" \n Did VN based subtype prop for index #%02u in " FMT_BB " :\n " , index, compCurBB->bbNum );
5167
+ DISPTREE (call);
5126
5168
5127
- return optAssertionProp_Update (arg1, call, stmt);
5169
+ objArg = gtWrapWithSideEffects (objArg, call, GTF_SIDE_EFFECT, true );
5170
+ return optAssertionProp_Update (objArg, call, stmt);
5128
5171
}
5129
5172
5130
5173
// Leave a hint for fgLateCastExpansion that obj is never null.
5131
5174
INDEBUG (AssertionIndex nonNullIdx = NO_ASSERTION_INDEX);
5132
5175
INDEBUG (bool vnBased = false );
5133
5176
// GTF_CALL_M_CAST_CAN_BE_EXPANDED check is to improve TP
5134
5177
if (((call->gtCallMoreFlags & GTF_CALL_M_CAST_CAN_BE_EXPANDED) != 0 ) &&
5135
- optAssertionIsNonNull (arg1 , assertions DEBUGARG (&vnBased) DEBUGARG (&nonNullIdx)))
5178
+ optAssertionIsNonNull (objArg , assertions DEBUGARG (&vnBased) DEBUGARG (&nonNullIdx)))
5136
5179
{
5137
5180
call->gtCallMoreFlags |= GTF_CALL_M_CAST_OBJ_NONNULL;
5138
5181
return optAssertionProp_Update (call, call, stmt);
@@ -6419,8 +6462,14 @@ Compiler::fgWalkResult Compiler::optVNConstantPropCurStmt(BasicBlock* block,
6419
6462
6420
6463
if (newTree == nullptr )
6421
6464
{
6422
- // Not propagated, keep going.
6423
- return WALK_CONTINUE;
6465
+ // If it wasn't a constant, let's see if we can reduce the strength
6466
+ // of the tree using VN.
6467
+ newTree = optVNStrengthReductionOnTree (block, parent, tree);
6468
+ if (newTree == nullptr )
6469
+ {
6470
+ // Not propagated, keep going.
6471
+ return WALK_CONTINUE;
6472
+ }
6424
6473
}
6425
6474
6426
6475
// TODO https://github.com/dotnet/runtime/issues/10450:
0 commit comments