Skip to content
11 changes: 11 additions & 0 deletions src/coreclr/jit/assertionprop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1307,6 +1307,17 @@ Compiler::AssertionDsc* Compiler::optGetAssertion(AssertionIndex assertIndex)
return assertion;
}

ValueNum Compiler::optConservativeNormalVN(GenTree* tree)
{
if (optLocalAssertionProp)
{
return ValueNumStore::NoVN;
}

assert(vnStore != nullptr);
return vnStore->VNConservativeNormalValue(tree->gtVNPair);
}

//------------------------------------------------------------------------
// optCastConstantSmall: Cast a constant to a small type.
//
Expand Down
7 changes: 0 additions & 7 deletions src/coreclr/jit/codegencommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4260,13 +4260,6 @@ void CodeGen::genCheckUseBlockInit()
continue;
}

// Initialization of OSR locals must be handled specially
if (compiler->lvaIsOSRLocal(varNum))
{
varDsc->lvMustInit = 0;
continue;
}

if (compiler->fgVarIsNeverZeroInitializedInProlog(varNum))
{
varDsc->lvMustInit = 0;
Expand Down
52 changes: 30 additions & 22 deletions src/coreclr/jit/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4746,29 +4746,31 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl
// At this point we know if we are fully interruptible or not
if (opts.OptimizationEnabled())
{
bool doSsa = true;
bool doEarlyProp = true;
bool doValueNum = true;
bool doLoopHoisting = true;
bool doCopyProp = true;
bool doBranchOpt = true;
bool doCse = true;
bool doAssertionProp = true;
bool doRangeAnalysis = true;
bool doIfConversion = true;
int iterations = 1;
bool doSsa = true;
bool doEarlyProp = true;
bool doValueNum = true;
bool doLoopHoisting = true;
bool doCopyProp = true;
bool doBranchOpt = true;
bool doCse = true;
bool doAssertionProp = true;
bool doRangeAnalysis = true;
bool doIfConversion = true;
bool doVNBasedDeadStoreRemoval = true;
int iterations = 1;

#if defined(OPT_CONFIG)
doSsa = (JitConfig.JitDoSsa() != 0);
doEarlyProp = doSsa && (JitConfig.JitDoEarlyProp() != 0);
doValueNum = doSsa && (JitConfig.JitDoValueNumber() != 0);
doLoopHoisting = doValueNum && (JitConfig.JitDoLoopHoisting() != 0);
doCopyProp = doValueNum && (JitConfig.JitDoCopyProp() != 0);
doBranchOpt = doValueNum && (JitConfig.JitDoRedundantBranchOpts() != 0);
doCse = doValueNum;
doAssertionProp = doValueNum && (JitConfig.JitDoAssertionProp() != 0);
doRangeAnalysis = doAssertionProp && (JitConfig.JitDoRangeAnalysis() != 0);
doIfConversion = doIfConversion && (JitConfig.JitDoIfConversion() != 0);
doSsa = (JitConfig.JitDoSsa() != 0);
doEarlyProp = doSsa && (JitConfig.JitDoEarlyProp() != 0);
doValueNum = doSsa && (JitConfig.JitDoValueNumber() != 0);
doLoopHoisting = doValueNum && (JitConfig.JitDoLoopHoisting() != 0);
doCopyProp = doValueNum && (JitConfig.JitDoCopyProp() != 0);
doBranchOpt = doValueNum && (JitConfig.JitDoRedundantBranchOpts() != 0);
doCse = doValueNum;
doAssertionProp = doValueNum && (JitConfig.JitDoAssertionProp() != 0);
doRangeAnalysis = doAssertionProp && (JitConfig.JitDoRangeAnalysis() != 0);
doIfConversion = doIfConversion && (JitConfig.JitDoIfConversion() != 0);
doVNBasedDeadStoreRemoval = doValueNum && (JitConfig.JitDoVNBasedDeadStoreRemoval() != 0);

if (opts.optRepeat)
{
Expand Down Expand Up @@ -4864,6 +4866,13 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl
DoPhase(this, PHASE_OPTIMIZE_INDEX_CHECKS, &Compiler::rangeCheckPhase);
}

if (doVNBasedDeadStoreRemoval)
{
// Note: this invalidates SSA and value numbers on tree nodes.
//
DoPhase(this, PHASE_VN_BASED_DEAD_STORE_REMOVAL, &Compiler::optVNBasedDeadStoreRemoval);
}

if (fgModified)
{
// update the flowgraph if we modified it during the optimization phase
Expand Down Expand Up @@ -9294,7 +9303,6 @@ void cTreeFlags(Compiler* comp, GenTree* tree)
genTreeOps op = tree->OperGet();
switch (op)
{

case GT_LCL_VAR:
case GT_LCL_VAR_ADDR:
case GT_LCL_FLD:
Expand Down
11 changes: 6 additions & 5 deletions src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -6054,10 +6054,6 @@ class Compiler
// Mark a loop as removed.
void optMarkLoopRemoved(unsigned loopNum);

// During global assertion prop, returns the conservative normal VN for a tree;
// otherwise returns NoVN
ValueNum optConservativeNormalVN(GenTree* tree);

private:
// Requires "lnum" to be the index of an outermost loop in the loop table. Traverses the body of that loop,
// including all nested loops, and records the set of "side effects" of the loop: fields (object instance and
Expand Down Expand Up @@ -6832,6 +6828,8 @@ class Compiler
}
};

PhaseStatus optVNBasedDeadStoreRemoval();

// clang-format off

#define OMF_HAS_NEWARRAY 0x00000001 // Method contains 'new' of an SD array
Expand Down Expand Up @@ -7333,14 +7331,17 @@ class Compiler
AssertionIndex optFindComplementary(AssertionIndex assertionIndex);
void optMapComplementary(AssertionIndex assertionIndex, AssertionIndex index);

ValueNum optConservativeNormalVN(GenTree* tree);

ssize_t optCastConstantSmall(ssize_t iconVal, var_types smallType);

// Assertion creation functions.
AssertionIndex optCreateAssertion(GenTree* op1,
GenTree* op2,
optAssertionKind assertionKind,
bool helperCallArgs = false);

AssertionIndex optFinalizeCreatingAssertion(AssertionDsc* assertion);
ssize_t optCastConstantSmall(ssize_t iconVal, var_types smallType);

bool optTryExtractSubrangeAssertion(GenTree* source, IntegralRange* pRange);

Expand Down
1 change: 1 addition & 0 deletions src/coreclr/jit/compphases.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ CompPhaseNameMacro(PHASE_VN_COPY_PROP, "VN based copy prop",
CompPhaseNameMacro(PHASE_OPTIMIZE_BRANCHES, "Redundant branch opts", false, -1, false)
CompPhaseNameMacro(PHASE_ASSERTION_PROP_MAIN, "Assertion prop", false, -1, false)
CompPhaseNameMacro(PHASE_IF_CONVERSION, "If conversion", false, -1, false)
CompPhaseNameMacro(PHASE_VN_BASED_DEAD_STORE_REMOVAL,"VN-based dead store removal", false, -1, false)
CompPhaseNameMacro(PHASE_OPT_UPDATE_FLOW_GRAPH, "Update flow graph opt pass", false, -1, false)
CompPhaseNameMacro(PHASE_COMPUTE_EDGE_WEIGHTS2, "Compute edge weights (2, false)",false, -1, false)
CompPhaseNameMacro(PHASE_INSERT_GC_POLLS, "Insert GC Polls", false, -1, true)
Expand Down
3 changes: 3 additions & 0 deletions src/coreclr/jit/jitconfigvalues.h
Original file line number Diff line number Diff line change
Expand Up @@ -419,9 +419,12 @@ CONFIG_INTEGER(JitDoEarlyProp, W("JitDoEarlyProp"), 1) // Perform Early Value Pr
CONFIG_INTEGER(JitDoLoopHoisting, W("JitDoLoopHoisting"), 1) // Perform loop hoisting on loop invariant values
CONFIG_INTEGER(JitDoLoopInversion, W("JitDoLoopInversion"), 1) // Perform loop inversion on "for/while" loops
CONFIG_INTEGER(JitDoRangeAnalysis, W("JitDoRangeAnalysis"), 1) // Perform range check analysis
CONFIG_INTEGER(JitDoVNBasedDeadStoreRemoval, W("JitDoVNBasedDeadStoreRemoval"), 1) // Perform VN-based dead store
// removal
CONFIG_INTEGER(JitDoRedundantBranchOpts, W("JitDoRedundantBranchOpts"), 1) // Perform redundant branch optimizations
CONFIG_STRING(JitEnableRboRange, W("JitEnableRboRange"))
CONFIG_STRING(JitEnableTailMergeRange, W("JitEnableTailMergeRange"))
CONFIG_STRING(JitEnableVNBasedDeadStoreRemovalRange, W("JitEnableVNBasedDeadStoreRemovalRange"))

CONFIG_INTEGER(JitDoSsa, W("JitDoSsa"), 1) // Perform Static Single Assignment (SSA) numbering on the variables
CONFIG_INTEGER(JitDoValueNumber, W("JitDoValueNumber"), 1) // Perform value numbering on method expressions
Expand Down
109 changes: 98 additions & 11 deletions src/coreclr/jit/optimizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10689,6 +10689,104 @@ void Compiler::optRemoveRedundantZeroInits()
}
}

//------------------------------------------------------------------------
// optVNBasedDeadStoreRemoval: VN(value)-based dead store removal.
//
// The phase iterates over partial stores referenced by the SSA
// descriptors and deletes those which do not change the local's value.
//
// Return Value:
// A suitable phase status.
//
PhaseStatus Compiler::optVNBasedDeadStoreRemoval()
{
#ifdef DEBUG
static ConfigMethodRange JitEnableVNBasedDeadStoreRemovalRange;
JitEnableVNBasedDeadStoreRemovalRange.EnsureInit(JitConfig.JitEnableVNBasedDeadStoreRemovalRange());

if (!JitEnableVNBasedDeadStoreRemovalRange.Contains(info.compMethodHash()))
{
JITDUMP("VN-based dead store removal disabled by JitEnableVNBasedDeadStoreRemovalRange\n");
return PhaseStatus::MODIFIED_NOTHING;
}
#endif

bool madeChanges = false;

for (unsigned lclNum = 0; lclNum < lvaCount; lclNum++)
{
if (!lvaInSsa(lclNum))
{
continue;
}

LclVarDsc* varDsc = lvaGetDesc(lclNum);
unsigned defCount = varDsc->lvPerSsaData.GetCount();
if (defCount <= 2)
{
continue;
}

for (unsigned defIndex = 1; defIndex < defCount; defIndex++)
{
LclSsaVarDsc* defDsc = varDsc->lvPerSsaData.GetSsaDefByIndex(defIndex);
GenTreeOp* store = defDsc->GetAssignment();

if (store != nullptr)
{
assert(store->OperIs(GT_ASG) && defDsc->m_vnPair.BothDefined());

JITDUMP("Considering [%06u] for removal...\n", dspTreeID(store));

GenTree* lhs = store->gtGetOp1();
if (!lhs->OperIs(GT_LCL_FLD) || ((lhs->gtFlags & GTF_VAR_USEASG) == 0) ||
(lhs->AsLclFld()->GetLclNum() != lclNum))
{
continue;
}

ValueNum oldLclValue = varDsc->GetPerSsaData(defDsc->GetUseDefSsaNum())->m_vnPair.GetConservative();
ValueNum oldStoreValue =
vnStore->VNForLoad(VNK_Conservative, oldLclValue, lvaLclExactSize(lclNum), lhs->TypeGet(),
lhs->AsLclFld()->GetLclOffs(), lhs->AsLclFld()->GetSize());

GenTree* rhs = store->gtGetOp2();
ValueNum storeValue;
if (lhs->TypeIs(TYP_STRUCT) && rhs->IsIntegralConst(0))
{
storeValue = vnStore->VNForZeroObj(lhs->AsLclFld()->GetLayout());
}
else
{
storeValue = rhs->GetVN(VNK_Conservative);
}

if (oldStoreValue == storeValue)
{
JITDUMP("Removed dead store:\n");
DISPTREE(store);

lhs->gtFlags &= ~(GTF_VAR_DEF | GTF_VAR_USEASG);

store->ChangeOper(GT_COMMA);
if (store->IsReverseOp())
{
std::swap(store->gtOp1, store->gtOp2);
store->ClearReverseOp();
}
store->gtType = store->gtGetOp2()->TypeGet();
store->SetAllEffectsFlags(store->gtOp1, store->gtOp2);
gtUpdateTreeAncestorsSideEffects(store);

madeChanges = true;
}
}
}
}

return madeChanges ? PhaseStatus::MODIFIED_EVERYTHING : PhaseStatus::MODIFIED_NOTHING;
}

#ifdef DEBUG

//------------------------------------------------------------------------
Expand Down Expand Up @@ -10930,14 +11028,3 @@ void Compiler::optMarkLoopRemoved(unsigned loopNum)
// `fgDebugCheckLoopTable()` is called.
#endif // DEBUG
}

ValueNum Compiler::optConservativeNormalVN(GenTree* tree)
{
if (optLocalAssertionProp)
{
return ValueNumStore::NoVN;
}

assert(vnStore != nullptr);
return vnStore->VNConservativeNormalValue(tree->gtVNPair);
}
6 changes: 5 additions & 1 deletion src/coreclr/jit/rationalize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -574,8 +574,12 @@ Compiler::fgWalkResult Rationalizer::RewriteNode(GenTree** useEdge, Compiler::Ge
// args as these have now been sequenced.
for (CallArg& arg : node->AsCall()->gtArgs.EarlyArgs())
{
if (!arg.GetEarlyNode()->IsValue())
if (arg.GetLateNode() != nullptr)
{
if (arg.GetEarlyNode()->IsValue())
{
arg.GetEarlyNode()->SetUnusedValue();
}
arg.SetEarlyNode(nullptr);
}
}
Expand Down
15 changes: 3 additions & 12 deletions src/coreclr/jit/valuenum.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7581,18 +7581,9 @@ PhaseStatus Compiler::fgValueNumber()
// The last clause covers the use-before-def variables (the ones that are live-in to the first block),
// these are variables that are read before being initialized (at least on some control flow paths)
// if they are not must-init, then they get VNF_InitVal(i), as with the param case.)

bool isZeroed = (info.compInitMem || varDsc->lvMustInit);

// For OSR, locals or promoted fields of locals may be missing the initial def
// because of partial importation. We can't assume they are zero.
if (lvaIsOSRLocal(lclNum))
{
isZeroed = false;
}

ValueNum initVal = ValueNumStore::NoVN; // We must assign a new value to initVal
var_types typ = varDsc->TypeGet();
bool isZeroed = !fgVarNeedsExplicitZeroInit(lclNum, /* bbInALoop */ false, /* bbIsReturn */ false);
ValueNum initVal = ValueNumStore::NoVN; // We must assign a new value to initVal
var_types typ = varDsc->TypeGet();

switch (typ)
{
Expand Down