@@ -3177,6 +3177,15 @@ GenTree* Compiler::optVNConstantPropOnTree(BasicBlock* block, GenTree* tree)
31773177
31783178 if (conValTree != nullptr )
31793179 {
3180+ if (tree->OperIs (GT_LCL_VAR))
3181+ {
3182+ if (!optIsProfitableToSubstitute (tree->AsLclVar (), block, conValTree))
3183+ {
3184+ // Not profitable to substitute
3185+ return nullptr ;
3186+ }
3187+ }
3188+
31803189 // Were able to optimize.
31813190 conValTree->gtVNPair = vnPair;
31823191 GenTree* sideEffList = optExtractSideEffListFromConst (tree);
@@ -3199,6 +3208,55 @@ GenTree* Compiler::optVNConstantPropOnTree(BasicBlock* block, GenTree* tree)
31993208 }
32003209}
32013210
3211+ // ------------------------------------------------------------------------------
3212+ // optIsProfitableToSubstitute: Checks if value worth substituting to lcl location
3213+ //
3214+ // Arguments:
3215+ // lcl - lcl to replace with value if profitable
3216+ // lclBlock - Basic block lcl located in
3217+ // value - value we plan to substitute to lcl
3218+ //
3219+ // Returns:
3220+ // False if it's likely not profitable to do substitution, True otherwise
3221+ //
3222+ bool Compiler::optIsProfitableToSubstitute (GenTreeLclVarCommon* lcl, BasicBlock* lclBlock, GenTree* value)
3223+ {
3224+ // A simple heuristic: If the constant is defined outside of a loop (not far from its head)
3225+ // and is used inside it - don't propagate.
3226+
3227+ // TODO: Extend on more kinds of trees
3228+ if (!value->OperIs (GT_CNS_VEC, GT_CNS_DBL))
3229+ {
3230+ return true ;
3231+ }
3232+
3233+ gtPrepareCost (value);
3234+
3235+ if ((value->GetCostEx () > 1 ) && (value->GetCostSz () > 1 ))
3236+ {
3237+ // Try to find the block this constant was originally defined in
3238+ if (lcl->HasSsaName ())
3239+ {
3240+ BasicBlock* defBlock = lvaGetDesc (lcl)->GetPerSsaData (lcl->GetSsaNum ())->GetBlock ();
3241+ if (defBlock != nullptr )
3242+ {
3243+ // Avoid propagating if the weighted use cost is significantly greater than the def cost.
3244+ // NOTE: this currently does not take "a float living across a call" case into account
3245+ // where we might end up with spill/restore on ABIs without callee-saved registers
3246+ const weight_t defBlockWeight = defBlock->getBBWeight (this );
3247+ const weight_t lclblockWeight = lclBlock->getBBWeight (this );
3248+
3249+ if ((defBlockWeight > 0 ) && ((lclblockWeight / defBlockWeight) >= BB_LOOP_WEIGHT_SCALE))
3250+ {
3251+ JITDUMP (" Constant propagation inside loop " FMT_BB " is not profitable\n " , lclBlock->bbNum );
3252+ return false ;
3253+ }
3254+ }
3255+ }
3256+ }
3257+ return true ;
3258+ }
3259+
32023260// ------------------------------------------------------------------------------
32033261// optConstantAssertionProp: Possibly substitute a constant for a local use
32043262//
0 commit comments