From b84813f62ca1c624e33fd5ed16ea76f5c64a0516 Mon Sep 17 00:00:00 2001 From: Vadim Sychev Date: Wed, 15 Dec 2021 02:07:51 +0300 Subject: [PATCH 01/13] Add optimization "X & 1 == 1" to "X & 1" (#61412) --- src/coreclr/jit/lower.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index e03d50e8d2f63..a201215b5658d 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -3123,6 +3123,22 @@ GenTree* Lowering::LowerCompare(GenTree* cmp) } #endif + // Optimizes (X & 1) == 1 to (X & 1) + // GTF_RELOP_JMP_USED is used to make sure the optimization is used for return statements only. + if (cmp->gtGetOp2()->IsIntegralConst(1) && cmp->gtGetOp1()->gtOper == GT_AND) + { + GenTree* op1 = cmp->gtGetOp1(); + + if (op1->gtGetOp1()->gtOper == GT_LCL_VAR && op1->gtGetOp2()->IsIntegralConst(1) && !(cmp->gtFlags & GTF_RELOP_JMP_USED)) + { + GenTree* next = cmp->gtNext; + BlockRange().Remove(cmp->gtGetOp2()); + BlockRange().Remove(cmp); + next->AsOp()->gtOp1 = op1; + return next; + } + } + if (cmp->gtGetOp2()->IsIntegralConst() && !comp->opts.MinOpts()) { GenTree* next = OptimizeConstCompare(cmp); From 3fc4ee3680f800c231796c4cdb6b43390b2d96dc Mon Sep 17 00:00:00 2001 From: Vadim Sychev Date: Thu, 16 Dec 2021 10:20:11 +0300 Subject: [PATCH 02/13] Moved the optimization to the morph phase (#61412) --- src/coreclr/jit/lower.cpp | 16 ---------------- src/coreclr/jit/morph.cpp | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index a201215b5658d..e03d50e8d2f63 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -3123,22 +3123,6 @@ GenTree* Lowering::LowerCompare(GenTree* cmp) } #endif - // Optimizes (X & 1) == 1 to (X & 1) - // GTF_RELOP_JMP_USED is used to make sure the optimization is used for return statements only. - if (cmp->gtGetOp2()->IsIntegralConst(1) && cmp->gtGetOp1()->gtOper == GT_AND) - { - GenTree* op1 = cmp->gtGetOp1(); - - if (op1->gtGetOp1()->gtOper == GT_LCL_VAR && op1->gtGetOp2()->IsIntegralConst(1) && !(cmp->gtFlags & GTF_RELOP_JMP_USED)) - { - GenTree* next = cmp->gtNext; - BlockRange().Remove(cmp->gtGetOp2()); - BlockRange().Remove(cmp); - next->AsOp()->gtOp1 = op1; - return next; - } - } - if (cmp->gtGetOp2()->IsIntegralConst() && !comp->opts.MinOpts()) { GenTree* next = OptimizeConstCompare(cmp); diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index ba331b8511ad8..376a0a3261dd8 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -11598,6 +11598,21 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac) } } } + + // Optimizes (X & 1) == 1 to (X & 1) + // GTF_RELOP_JMP_USED is used to make sure the optimization is used for return statements only. + if (tree->gtGetOp2()->IsIntegralConst(1) && tree->gtGetOp1()->OperIs(GT_AND) && !(tree->gtFlags & GTF_RELOP_JMP_USED)) + { + GenTree* op1 = tree->gtGetOp1(); + + if (op1->gtGetOp2()->IsIntegralConst(1)) + { + DEBUG_DESTROY_NODE(tree->gtGetOp2()); + DEBUG_DESTROY_NODE(tree); + + return fgMorphTree(op1); + } + } } FALLTHROUGH; From b1d57dc5dc7871d83c1b3b6081de105bbbce2f84 Mon Sep 17 00:00:00 2001 From: Vadim Sychev Date: Thu, 16 Dec 2021 12:10:12 +0300 Subject: [PATCH 03/13] Done in post-order (#61412) --- src/coreclr/jit/morph.cpp | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index 376a0a3261dd8..c2cc72fb90f76 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -11598,21 +11598,6 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac) } } } - - // Optimizes (X & 1) == 1 to (X & 1) - // GTF_RELOP_JMP_USED is used to make sure the optimization is used for return statements only. - if (tree->gtGetOp2()->IsIntegralConst(1) && tree->gtGetOp1()->OperIs(GT_AND) && !(tree->gtFlags & GTF_RELOP_JMP_USED)) - { - GenTree* op1 = tree->gtGetOp1(); - - if (op1->gtGetOp2()->IsIntegralConst(1)) - { - DEBUG_DESTROY_NODE(tree->gtGetOp2()); - DEBUG_DESTROY_NODE(tree); - - return fgMorphTree(op1); - } - } } FALLTHROUGH; @@ -12201,6 +12186,23 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac) op1 = tree->gtGetOp1(); op2 = tree->gtGetOp2(); } + + // Optimizes (X & 1) == 1 to (X & 1) + // GTF_RELOP_JMP_USED is used to make sure the optimization is used for return statements only. + if (tree->gtGetOp2()->IsIntegralConst(1) && tree->gtGetOp1()->OperIs(GT_AND) && + !(tree->gtFlags & GTF_RELOP_JMP_USED)) + { + GenTree* op1 = tree->gtGetOp1(); + + if (op1->gtGetOp2()->IsIntegralConst(1)) + { + DEBUG_DESTROY_NODE(tree->gtGetOp2()); + DEBUG_DESTROY_NODE(tree); + + return op1; + } + } + goto COMPARE; case GT_LT: From 9e7d39ade7a21ce274703a68a1cf7c65b4f62df3 Mon Sep 17 00:00:00 2001 From: Vadim Sychev Date: Thu, 16 Dec 2021 13:30:29 +0300 Subject: [PATCH 04/13] Moved the optimization into fgOptimizeEqualityComparisonWithConst (#61412) --- src/coreclr/jit/morph.cpp | 40 ++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index c2cc72fb90f76..c87c9e7479e02 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -12180,30 +12180,12 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac) if (!optValnumCSE_phase && op2->IsIntegralConst()) { tree = fgOptimizeEqualityComparisonWithConst(tree->AsOp()); - assert(tree->OperIsCompare()); oper = tree->OperGet(); op1 = tree->gtGetOp1(); op2 = tree->gtGetOp2(); } - - // Optimizes (X & 1) == 1 to (X & 1) - // GTF_RELOP_JMP_USED is used to make sure the optimization is used for return statements only. - if (tree->gtGetOp2()->IsIntegralConst(1) && tree->gtGetOp1()->OperIs(GT_AND) && - !(tree->gtFlags & GTF_RELOP_JMP_USED)) - { - GenTree* op1 = tree->gtGetOp1(); - - if (op1->gtGetOp2()->IsIntegralConst(1)) - { - DEBUG_DESTROY_NODE(tree->gtGetOp2()); - DEBUG_DESTROY_NODE(tree); - - return op1; - } - } - - goto COMPARE; + break; case GT_LT: case GT_LE: @@ -13388,6 +13370,26 @@ GenTree* Compiler::fgOptimizeEqualityComparisonWithConst(GenTreeOp* cmp) DEBUG_DESTROY_NODE(rshiftOp->gtGetOp2()); DEBUG_DESTROY_NODE(rshiftOp); } + + // Optimizes (X & 1) == 1 to (X & 1) + // + // EQ/NE AND + // / \ / \. + // AND CNS 1 -> x CNS 1 + // / \ + // x CNS 1 + // + // GTF_RELOP_JMP_USED is used to make sure the optimization is used for return statements only. + if (op1->OperIs(GT_AND) && !(cmp->gtFlags & GTF_RELOP_JMP_USED)) + { + if (op1->gtGetOp2()->IsIntegralConst(1)) + { + DEBUG_DESTROY_NODE(cmp->gtGetOp2()); + DEBUG_DESTROY_NODE(cmp); + + return op1; + } + } } SKIP: From 232500b0498a7225dff10c0e19880593109fc8e9 Mon Sep 17 00:00:00 2001 From: Vadim Sychev Date: Thu, 16 Dec 2021 14:20:52 +0300 Subject: [PATCH 05/13] Some corrections due the comments (#61412) --- src/coreclr/jit/morph.cpp | 42 +++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index c87c9e7479e02..ac13843f69a4c 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -13217,7 +13217,7 @@ GenTree* Compiler::fgOptimizeCast(GenTreeCast* cast) // // Return Value: // The optimized tree, "cmp" in case no optimizations were done. -// Currently only returns relop trees. +// Currently only returns GTK_SMPOP trees. // GenTree* Compiler::fgOptimizeEqualityComparisonWithConst(GenTreeOp* cmp) { @@ -13266,6 +13266,26 @@ GenTree* Compiler::fgOptimizeEqualityComparisonWithConst(GenTreeOp* cmp) { ssize_t op2Value = static_cast(op2->IntegralValue()); + // Optimizes (X & 1) == 1 to (X & 1) + // + // EQ/NE AND + // / \ / \. + // AND CNS 1 -> x CNS 1 + // / \ + // x CNS 1 + // + // The compiler requires jumps to have relop operands, so we do not fold that case. + if (op1->OperIs(GT_AND) && op2Value == 1 && !(cmp->gtFlags & GTF_RELOP_JMP_USED)) + { + if (op1->gtGetOp2()->IsIntegralConst(1)) + { + DEBUG_DESTROY_NODE(op2); + DEBUG_DESTROY_NODE(cmp); + + return op1; + } + } + if (op1->OperIsCompare()) { // Here we look for the following tree @@ -13370,26 +13390,6 @@ GenTree* Compiler::fgOptimizeEqualityComparisonWithConst(GenTreeOp* cmp) DEBUG_DESTROY_NODE(rshiftOp->gtGetOp2()); DEBUG_DESTROY_NODE(rshiftOp); } - - // Optimizes (X & 1) == 1 to (X & 1) - // - // EQ/NE AND - // / \ / \. - // AND CNS 1 -> x CNS 1 - // / \ - // x CNS 1 - // - // GTF_RELOP_JMP_USED is used to make sure the optimization is used for return statements only. - if (op1->OperIs(GT_AND) && !(cmp->gtFlags & GTF_RELOP_JMP_USED)) - { - if (op1->gtGetOp2()->IsIntegralConst(1)) - { - DEBUG_DESTROY_NODE(cmp->gtGetOp2()); - DEBUG_DESTROY_NODE(cmp); - - return op1; - } - } } SKIP: From 4e199b404d6c9fee1ea03fa9f7c7b27ce64dc264 Mon Sep 17 00:00:00 2001 From: Vadim Sychev Date: Fri, 17 Dec 2021 13:27:05 +0300 Subject: [PATCH 06/13] Fix of the picture (#61412) --- src/coreclr/jit/morph.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index ac13843f69a4c..4d3603f34cafa 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -13271,7 +13271,7 @@ GenTree* Compiler::fgOptimizeEqualityComparisonWithConst(GenTreeOp* cmp) // EQ/NE AND // / \ / \. // AND CNS 1 -> x CNS 1 - // / \ + // / \. // x CNS 1 // // The compiler requires jumps to have relop operands, so we do not fold that case. From 4e33287bbebf728324d3db671b5b778840da1151 Mon Sep 17 00:00:00 2001 From: Vadim Sychev Date: Wed, 22 Dec 2021 11:24:17 +0300 Subject: [PATCH 07/13] Add optNarrowTree use (#61412) --- src/coreclr/jit/morph.cpp | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index 4d3603f34cafa..474d86e614800 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -13266,26 +13266,31 @@ GenTree* Compiler::fgOptimizeEqualityComparisonWithConst(GenTreeOp* cmp) { ssize_t op2Value = static_cast(op2->IntegralValue()); - // Optimizes (X & 1) == 1 to (X & 1) - // - // EQ/NE AND - // / \ / \. - // AND CNS 1 -> x CNS 1 - // / \. - // x CNS 1 - // - // The compiler requires jumps to have relop operands, so we do not fold that case. - if (op1->OperIs(GT_AND) && op2Value == 1 && !(cmp->gtFlags & GTF_RELOP_JMP_USED)) + if (fgGlobalMorph) { - if (op1->gtGetOp2()->IsIntegralConst(1)) + // Optimizes (X & 1) == 1 to (X & 1) + // + // EQ/NE AND + // / \ / \. + // AND CNS 1 -> x CNS 1 + // / \. + // x CNS 1 + // + // The compiler requires jumps to have relop operands, so we do not fold that case. + if (op1->OperIs(GT_AND) && (op2Value == 1) && !(cmp->gtFlags & GTF_RELOP_JMP_USED)) { - DEBUG_DESTROY_NODE(op2); - DEBUG_DESTROY_NODE(cmp); + if (op1->gtGetOp2()->IsIntegralConst(1)) + { + + DEBUG_DESTROY_NODE(op2); + DEBUG_DESTROY_NODE(cmp); - return op1; + optNarrowTree(op1, op1->TypeGet(), TYP_INT, ValueNumPair(), true); + + return op1; + } } } - if (op1->OperIsCompare()) { // Here we look for the following tree From 9011df3a01be9c27b81e374e3d2b1a4e6904a0d0 Mon Sep 17 00:00:00 2001 From: Vadim Sychev Date: Sat, 25 Dec 2021 00:39:32 +0300 Subject: [PATCH 08/13] Change narrowing to the type check (#61412) --- src/coreclr/jit/morph.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index 474d86e614800..544ae1c4030cc 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -13279,14 +13279,12 @@ GenTree* Compiler::fgOptimizeEqualityComparisonWithConst(GenTreeOp* cmp) // The compiler requires jumps to have relop operands, so we do not fold that case. if (op1->OperIs(GT_AND) && (op2Value == 1) && !(cmp->gtFlags & GTF_RELOP_JMP_USED)) { - if (op1->gtGetOp2()->IsIntegralConst(1)) + if (op1->gtGetOp2()->IsIntegralConst(1) && (genActualType(op1) == cmp->TypeGet())) { - + DEBUG_DESTROY_NODE(op2); DEBUG_DESTROY_NODE(cmp); - optNarrowTree(op1, op1->TypeGet(), TYP_INT, ValueNumPair(), true); - return op1; } } From 45ebaa42a04eeaa4706d9853c03753dea30741c9 Mon Sep 17 00:00:00 2001 From: Vadim Sychev Date: Tue, 28 Dec 2021 01:40:13 +0300 Subject: [PATCH 09/13] Fix regressions (#61412) --- src/coreclr/jit/morph.cpp | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index 544ae1c4030cc..3f069961344cb 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -13266,29 +13266,29 @@ GenTree* Compiler::fgOptimizeEqualityComparisonWithConst(GenTreeOp* cmp) { ssize_t op2Value = static_cast(op2->IntegralValue()); - if (fgGlobalMorph) + // Optimizes (X & 1) == 1 to (X & 1) + // + // EQ/NE AND + // / \ / \. + // AND CNS 1 -> x CNS 1 + // / \. + // x CNS 1 + // + // The compiler requires jumps to have relop operands, so we do not fold that case. + if (op1->OperIs(GT_AND) && (op2Value == 1) && !(cmp->gtFlags & GTF_RELOP_JMP_USED)) { - // Optimizes (X & 1) == 1 to (X & 1) - // - // EQ/NE AND - // / \ / \. - // AND CNS 1 -> x CNS 1 - // / \. - // x CNS 1 - // - // The compiler requires jumps to have relop operands, so we do not fold that case. - if (op1->OperIs(GT_AND) && (op2Value == 1) && !(cmp->gtFlags & GTF_RELOP_JMP_USED)) + if ((op1->gtGetOp1()->gtOper == GT_LCL_VAR) && op1->gtGetOp2()->IsIntegralConst(1) && + (genActualType(op1) == cmp->TypeGet())) { - if (op1->gtGetOp2()->IsIntegralConst(1) && (genActualType(op1) == cmp->TypeGet())) - { + op1->SetVNsFromNode(cmp); - DEBUG_DESTROY_NODE(op2); - DEBUG_DESTROY_NODE(cmp); + DEBUG_DESTROY_NODE(op2); + DEBUG_DESTROY_NODE(cmp); - return op1; - } + return op1; } } + if (op1->OperIsCompare()) { // Here we look for the following tree From 0bf59656b62069facdb08d1b819a240ca22ec944 Mon Sep 17 00:00:00 2001 From: Vadim Sychev Date: Mon, 10 Jan 2022 10:53:28 +0300 Subject: [PATCH 10/13] Moved the optimization to the lowering phase (#61412) --- src/coreclr/jit/lower.cpp | 30 ++++++++++++++++++++++++++++++ src/coreclr/jit/morph.cpp | 23 ----------------------- 2 files changed, 30 insertions(+), 23 deletions(-) diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index e03d50e8d2f63..2014dfd7dbcac 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -3123,6 +3123,36 @@ GenTree* Lowering::LowerCompare(GenTree* cmp) } #endif + // Optimizes (X & 1) == 1 to (X & 1) + // + // EQ/NE AND + // / \ / \. + // AND CNS 1 -> x CNS 1 + // / \. + // x CNS 1 + // + // The compiler requires jumps to have relop operands, so we do not fold that case. + if (cmp->gtGetOp1()->OperIs(GT_AND) && cmp->gtGetOp2()->IsIntegralConst(1) && !(cmp->gtFlags & GTF_RELOP_JMP_USED)) + { + GenTree* op1 = cmp->gtGetOp1(); + if (op1->gtGetOp2()->IsIntegralConst(1) && (genActualType(op1) == cmp->TypeGet())) + { + LIR::Use use; + + GenTree* next = cmp->gtNext; + + if (BlockRange().TryGetUse(cmp, &use)) + { + use.ReplaceWith(op1); + } + + BlockRange().Remove(cmp->gtGetOp2()); + BlockRange().Remove(cmp); + + return next; + } + } + if (cmp->gtGetOp2()->IsIntegralConst() && !comp->opts.MinOpts()) { GenTree* next = OptimizeConstCompare(cmp); diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index 3f069961344cb..83349b18929bb 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -13266,29 +13266,6 @@ GenTree* Compiler::fgOptimizeEqualityComparisonWithConst(GenTreeOp* cmp) { ssize_t op2Value = static_cast(op2->IntegralValue()); - // Optimizes (X & 1) == 1 to (X & 1) - // - // EQ/NE AND - // / \ / \. - // AND CNS 1 -> x CNS 1 - // / \. - // x CNS 1 - // - // The compiler requires jumps to have relop operands, so we do not fold that case. - if (op1->OperIs(GT_AND) && (op2Value == 1) && !(cmp->gtFlags & GTF_RELOP_JMP_USED)) - { - if ((op1->gtGetOp1()->gtOper == GT_LCL_VAR) && op1->gtGetOp2()->IsIntegralConst(1) && - (genActualType(op1) == cmp->TypeGet())) - { - op1->SetVNsFromNode(cmp); - - DEBUG_DESTROY_NODE(op2); - DEBUG_DESTROY_NODE(cmp); - - return op1; - } - } - if (op1->OperIsCompare()) { // Here we look for the following tree From f62c64b6e66ce58fa2317a485957a320de7b335f Mon Sep 17 00:00:00 2001 From: Vadim Sychev Date: Tue, 11 Jan 2022 11:05:06 +0300 Subject: [PATCH 11/13] Reverted Morph changes (#61412) --- src/coreclr/jit/morph.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index 83349b18929bb..ba331b8511ad8 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -12180,12 +12180,13 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac) if (!optValnumCSE_phase && op2->IsIntegralConst()) { tree = fgOptimizeEqualityComparisonWithConst(tree->AsOp()); + assert(tree->OperIsCompare()); oper = tree->OperGet(); op1 = tree->gtGetOp1(); op2 = tree->gtGetOp2(); } - break; + goto COMPARE; case GT_LT: case GT_LE: @@ -13217,7 +13218,7 @@ GenTree* Compiler::fgOptimizeCast(GenTreeCast* cast) // // Return Value: // The optimized tree, "cmp" in case no optimizations were done. -// Currently only returns GTK_SMPOP trees. +// Currently only returns relop trees. // GenTree* Compiler::fgOptimizeEqualityComparisonWithConst(GenTreeOp* cmp) { From f64a8aca6ad13a82964fbc441b7e35372a365f44 Mon Sep 17 00:00:00 2001 From: Vadim Sychev Date: Wed, 12 Jan 2022 16:56:01 +0300 Subject: [PATCH 12/13] Moved the optimization into OptimizeConstCompare method (#61412) --- src/coreclr/jit/lower.cpp | 49 +++++++++++++++------------------------ 1 file changed, 19 insertions(+), 30 deletions(-) diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index 2014dfd7dbcac..18d7c4260f64c 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -2925,6 +2925,25 @@ GenTree* Lowering::OptimizeConstCompare(GenTree* cmp) if (op2Value != 0) { + // Optimizes (X & 1) == 1 to (X & 1) + // The compiler requires jumps to have relop operands, so we do not fold that case. + LIR::Use cmpUse; + if ((op2Value == 1) && BlockRange().TryGetUse(cmp, &cmpUse)) + { + if (andOp2->IsIntegralConst(1) && (genActualType(op1) == cmp->TypeGet()) && + !cmpUse.User()->OperIs(GT_JTRUE)) + { + GenTree* next = cmp->gtNext; + + cmpUse.ReplaceWith(op1); + + BlockRange().Remove(cmp->gtGetOp2()); + BlockRange().Remove(cmp); + + return next; + } + } + // // If we don't have a 0 compare we can get one by transforming ((x AND mask) EQ|NE mask) // into ((x AND mask) NE|EQ 0) when mask is a single bit. @@ -3123,36 +3142,6 @@ GenTree* Lowering::LowerCompare(GenTree* cmp) } #endif - // Optimizes (X & 1) == 1 to (X & 1) - // - // EQ/NE AND - // / \ / \. - // AND CNS 1 -> x CNS 1 - // / \. - // x CNS 1 - // - // The compiler requires jumps to have relop operands, so we do not fold that case. - if (cmp->gtGetOp1()->OperIs(GT_AND) && cmp->gtGetOp2()->IsIntegralConst(1) && !(cmp->gtFlags & GTF_RELOP_JMP_USED)) - { - GenTree* op1 = cmp->gtGetOp1(); - if (op1->gtGetOp2()->IsIntegralConst(1) && (genActualType(op1) == cmp->TypeGet())) - { - LIR::Use use; - - GenTree* next = cmp->gtNext; - - if (BlockRange().TryGetUse(cmp, &use)) - { - use.ReplaceWith(op1); - } - - BlockRange().Remove(cmp->gtGetOp2()); - BlockRange().Remove(cmp); - - return next; - } - } - if (cmp->gtGetOp2()->IsIntegralConst() && !comp->opts.MinOpts()) { GenTree* next = OptimizeConstCompare(cmp); From 175bac29c63c5d79d58e43b1ee2deca4d8009ee2 Mon Sep 17 00:00:00 2001 From: Vadim Sychev Date: Tue, 18 Jan 2022 21:19:05 +0300 Subject: [PATCH 13/13] Add GT_EQ check(#61412) --- src/coreclr/jit/lower.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index 18d7c4260f64c..bd7c0b7b5e0bf 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -2928,10 +2928,10 @@ GenTree* Lowering::OptimizeConstCompare(GenTree* cmp) // Optimizes (X & 1) == 1 to (X & 1) // The compiler requires jumps to have relop operands, so we do not fold that case. LIR::Use cmpUse; - if ((op2Value == 1) && BlockRange().TryGetUse(cmp, &cmpUse)) + if ((op2Value == 1) && cmp->OperIs(GT_EQ)) { if (andOp2->IsIntegralConst(1) && (genActualType(op1) == cmp->TypeGet()) && - !cmpUse.User()->OperIs(GT_JTRUE)) + BlockRange().TryGetUse(cmp, &cmpUse) && !cmpUse.User()->OperIs(GT_JTRUE)) { GenTree* next = cmp->gtNext;