From c8556cca267d355de8755a4c925d0254c96f14d8 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Wed, 11 Feb 2026 20:17:45 +0100 Subject: [PATCH 1/5] Remove nullcheck effect from array len (global AP) --- src/coreclr/jit/assertionprop.cpp | 19 ++++++++++++++++--- src/coreclr/jit/gentree.cpp | 3 +++ src/coreclr/jit/optimizebools.cpp | 1 + 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/coreclr/jit/assertionprop.cpp b/src/coreclr/jit/assertionprop.cpp index 793c7944791049..6e37293c59e7c6 100644 --- a/src/coreclr/jit/assertionprop.cpp +++ b/src/coreclr/jit/assertionprop.cpp @@ -4589,7 +4589,7 @@ GenTree* Compiler::optAssertionProp_Comma(ASSERT_VALARG_TP assertions, GenTree* // GenTree* Compiler::optAssertionProp_Ind(ASSERT_VALARG_TP assertions, GenTree* tree, Statement* stmt) { - assert(tree->OperIsIndir()); + assert(tree->GetIndirOrArrMetaDataAddr()); bool updated = optNonNullAssertionProp_Ind(assertions, tree); if (tree->OperIs(GT_STOREIND)) @@ -4776,14 +4776,14 @@ GenTree* Compiler::optNonNullAssertionProp_Call(ASSERT_VALARG_TP assertions, Gen // bool Compiler::optNonNullAssertionProp_Ind(ASSERT_VALARG_TP assertions, GenTree* indir) { - assert(indir->OperIsIndir()); + assert(indir->GetIndirOrArrMetaDataAddr()); if ((indir->gtFlags & GTF_EXCEPT) == 0) { return false; } - if (optAssertionIsNonNull(indir->AsIndir()->Addr(), assertions)) + if (optAssertionIsNonNull(indir->GetIndirOrArrMetaDataAddr(), assertions)) { JITDUMP("Non-null assertion prop for indirection [%06d] in " FMT_BB ":\n", dspTreeID(indir), compCurBB->bbNum); @@ -5296,6 +5296,19 @@ GenTree* Compiler::optAssertionProp(ASSERT_VALARG_TP assertions, GenTree* tree, case GT_UDIV: return optAssertionProp_ModDiv(assertions, tree->AsOp(), stmt, block); + case GT_MDARR_LENGTH: + case GT_MDARR_LOWER_BOUND: + case GT_ARR_LENGTH: + // Unfortunately, doing this in LocalAP produces an asymmetry in exception sets between + // uses/defs that CSE does not manage to make good use of. As a result, some bounds checks are no longer + // removed. + // TODO-CSE: Allow CSE'ing uses with defs if the defs promise a superset of exceptions + if (!optLocalAssertionProp) + { + return optAssertionProp_Ind(assertions, tree, stmt); + } + return nullptr; + case GT_BLK: case GT_IND: case GT_STOREIND: diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index afc628d6c4a2ae..7d4913a1d36ed8 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -7554,6 +7554,9 @@ bool GenTree::OperSupportsOrderingSideEffect() const switch (OperGet()) { + case GT_ARR_LENGTH: + case GT_MDARR_LENGTH: + case GT_MDARR_LOWER_BOUND: case GT_ARR_ADDR: case GT_BOUNDS_CHECK: case GT_IND: diff --git a/src/coreclr/jit/optimizebools.cpp b/src/coreclr/jit/optimizebools.cpp index 24adf6778e5c30..f9ca5451dd56d6 100644 --- a/src/coreclr/jit/optimizebools.cpp +++ b/src/coreclr/jit/optimizebools.cpp @@ -1209,6 +1209,7 @@ void OptBoolsDsc::optOptimizeBoolsUpdateTrees() { m_compiler->gtSetStmtInfo(m_testInfo1.testStmt); m_compiler->fgSetStmtSeq(m_testInfo1.testStmt); + m_compiler->gtUpdateStmtSideEffects(m_testInfo1.testStmt); } /* Modify the target of the conditional jump and update bbRefs and bbPreds */ From e63264c872d877259eaa63ff79f1bc553d044e74 Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Wed, 11 Feb 2026 20:27:20 +0100 Subject: [PATCH 2/5] Update src/coreclr/jit/assertionprop.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/coreclr/jit/assertionprop.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/assertionprop.cpp b/src/coreclr/jit/assertionprop.cpp index 6e37293c59e7c6..4b05f6b48a12be 100644 --- a/src/coreclr/jit/assertionprop.cpp +++ b/src/coreclr/jit/assertionprop.cpp @@ -4589,7 +4589,7 @@ GenTree* Compiler::optAssertionProp_Comma(ASSERT_VALARG_TP assertions, GenTree* // GenTree* Compiler::optAssertionProp_Ind(ASSERT_VALARG_TP assertions, GenTree* tree, Statement* stmt) { - assert(tree->GetIndirOrArrMetaDataAddr()); + assert(tree->OperIsIndirOrArrMetaData()); bool updated = optNonNullAssertionProp_Ind(assertions, tree); if (tree->OperIs(GT_STOREIND)) From c494072fe855dbe5ab52fb8d84bf20fe7a347ad2 Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Wed, 11 Feb 2026 20:27:27 +0100 Subject: [PATCH 3/5] Update src/coreclr/jit/assertionprop.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/coreclr/jit/assertionprop.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/assertionprop.cpp b/src/coreclr/jit/assertionprop.cpp index 4b05f6b48a12be..cc8d650ce92942 100644 --- a/src/coreclr/jit/assertionprop.cpp +++ b/src/coreclr/jit/assertionprop.cpp @@ -4776,7 +4776,7 @@ GenTree* Compiler::optNonNullAssertionProp_Call(ASSERT_VALARG_TP assertions, Gen // bool Compiler::optNonNullAssertionProp_Ind(ASSERT_VALARG_TP assertions, GenTree* indir) { - assert(indir->GetIndirOrArrMetaDataAddr()); + assert(indir->OperIsIndirOrArrMetaData()); if ((indir->gtFlags & GTF_EXCEPT) == 0) { From 777b6ffbd0fd900fb74dede96ed44e56d71f8cb7 Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Thu, 12 Feb 2026 01:58:29 +0100 Subject: [PATCH 4/5] Disable MD array length and lower bound assertions Comment out MD array length and lower bound cases for optimization. --- src/coreclr/jit/assertionprop.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/coreclr/jit/assertionprop.cpp b/src/coreclr/jit/assertionprop.cpp index cc8d650ce92942..5079de7c7b9952 100644 --- a/src/coreclr/jit/assertionprop.cpp +++ b/src/coreclr/jit/assertionprop.cpp @@ -5296,9 +5296,10 @@ GenTree* Compiler::optAssertionProp(ASSERT_VALARG_TP assertions, GenTree* tree, case GT_UDIV: return optAssertionProp_ModDiv(assertions, tree->AsOp(), stmt, block); - case GT_MDARR_LENGTH: - case GT_MDARR_LOWER_BOUND: case GT_ARR_LENGTH: + // TODO-CQ: Enable for MD arrays as well (produces massive size regressions currently). + // case GT_MDARR_LENGTH: + // case GT_MDARR_LOWER_BOUND: // Unfortunately, doing this in LocalAP produces an asymmetry in exception sets between // uses/defs that CSE does not manage to make good use of. As a result, some bounds checks are no longer // removed. From 6ab5b18a3e68eb4b3f5d114821272277b71af678 Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Thu, 12 Feb 2026 02:26:21 +0100 Subject: [PATCH 5/5] Update assertionprop.cpp --- src/coreclr/jit/assertionprop.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/coreclr/jit/assertionprop.cpp b/src/coreclr/jit/assertionprop.cpp index 5079de7c7b9952..5e7d35b8255bf4 100644 --- a/src/coreclr/jit/assertionprop.cpp +++ b/src/coreclr/jit/assertionprop.cpp @@ -5297,9 +5297,6 @@ GenTree* Compiler::optAssertionProp(ASSERT_VALARG_TP assertions, GenTree* tree, return optAssertionProp_ModDiv(assertions, tree->AsOp(), stmt, block); case GT_ARR_LENGTH: - // TODO-CQ: Enable for MD arrays as well (produces massive size regressions currently). - // case GT_MDARR_LENGTH: - // case GT_MDARR_LOWER_BOUND: // Unfortunately, doing this in LocalAP produces an asymmetry in exception sets between // uses/defs that CSE does not manage to make good use of. As a result, some bounds checks are no longer // removed.