From c3b95718fb348a6eb1ae07f391b742b1ea72627a Mon Sep 17 00:00:00 2001 From: pedrobsaila Date: Wed, 23 Nov 2022 22:58:34 +0100 Subject: [PATCH 1/9] fuse < and > with = when applicable --- src/coreclr/jit/optimizer.cpp | 191 +++++++- .../JIT/opt/OptimizeBools/optboolsreturn.cs | 423 ++++++++++++++++++ 2 files changed, 603 insertions(+), 11 deletions(-) diff --git a/src/coreclr/jit/optimizer.cpp b/src/coreclr/jit/optimizer.cpp index be12db114d5782..7e00187f76cbdc 100644 --- a/src/coreclr/jit/optimizer.cpp +++ b/src/coreclr/jit/optimizer.cpp @@ -9486,12 +9486,7 @@ bool OptBoolsDsc::optOptimizeBoolsCondBlock() { // Both conditions must be the same - if (m_testInfo1.compTree->gtOper != m_testInfo2.compTree->gtOper) - { - return false; - } - - if (m_testInfo1.compTree->gtOper == GT_EQ) + if (m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_EQ) { // t1:c1==0 t2:c2==0 ==> Branch to BX if either value is 0 // So we will branch to BX if (c1&c2)==0 @@ -9499,7 +9494,7 @@ bool OptBoolsDsc::optOptimizeBoolsCondBlock() foldOp = GT_AND; cmpOp = GT_EQ; } - else if (m_testInfo1.compTree->gtOper == GT_LT) + else if (m_testInfo1.compTree->gtOper == GT_LT && m_testInfo2.compTree->gtOper == GT_LT) { // t1:c1<0 t2:c2<0 ==> Branch to BX if either value < 0 // So we will branch to BX if (c1|c2)<0 @@ -9507,11 +9502,11 @@ bool OptBoolsDsc::optOptimizeBoolsCondBlock() foldOp = GT_OR; cmpOp = GT_LT; } - else if (m_testInfo1.compTree->gtOper == GT_GE) + else if (m_testInfo1.compTree->gtOper == GT_GE && m_testInfo2.compTree->gtOper == GT_GE) { return false; } - else + else if (m_testInfo1.compTree->gtOper == GT_NE && m_testInfo2.compTree->gtOper == GT_NE) { // t1:c1!=0 t2:c2!=0 ==> Branch to BX if either value is non-0 // So we will branch to BX if (c1|c2)!=0 @@ -9519,6 +9514,40 @@ bool OptBoolsDsc::optOptimizeBoolsCondBlock() foldOp = GT_OR; cmpOp = GT_NE; } + else if (m_c1->gtOper == GT_LCL_VAR && m_c2->gtOper == GT_LCL_VAR && + m_c1->AsLclVarCommon()->GetLclNum() == m_c2->AsLclVarCommon()->GetLclNum()) + { + if ((m_testInfo1.compTree->gtOper == GT_LT && m_testInfo2.compTree->gtOper == GT_EQ) || + (m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_LT)) + { + // Case: t1:c1<0 t2:c1==0 + // So we will branch to BX if c1<=0 + // + // Case: t1:c1==0 t2:c1<0 + // So we will branch to BX if c1<=0 + cmpOp = GT_LE; + } + else if ((m_testInfo1.compTree->gtOper == GT_GT && m_testInfo2.compTree->gtOper == GT_EQ) || + (m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_GT)) + { + // Case: t1:c1>0 t2:c1==0 + // So we will branch to BX if c1>=0 + // + // Case: t1:c1==0 t2:c1>0 + // So we will branch to BX if c1>=0 + cmpOp = GT_GE; + } + else + { + return false; + } + + foldOp = GT_NONE; + } + else + { + return false; + } } else { @@ -9555,6 +9584,36 @@ bool OptBoolsDsc::optOptimizeBoolsCondBlock() foldOp = GT_OR; cmpOp = GT_EQ; } + else if (m_c1->gtOper == GT_LCL_VAR && m_c2->gtOper == GT_LCL_VAR && + m_c1->AsLclVarCommon()->GetLclNum() == m_c2->AsLclVarCommon()->GetLclNum()) + { + if ((m_testInfo1.compTree->gtOper == GT_LT && m_testInfo2.compTree->gtOper == GT_NE) || + (m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_GE)) + { + // Case: t1:c1<0 t2:c1!=0 + // So we will branch to BX if c1>0 + // + // Case: t1:c1==0 t2:c1>=0 + // So we will branch to BX if c1>0 + cmpOp = GT_GT; + } + else if ((m_testInfo1.compTree->gtOper == GT_GT && m_testInfo2.compTree->gtOper == GT_NE) || + (m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_LE)) + { + // Case: t1:c1>0 t2:c1!=0 + // So we will branch to BX if c1<0 + // + // Case: t1:c1==0 t2:c1<=0 + // So we will branch to BX if c1<0 + cmpOp = GT_LT; + } + else + { + return false; + } + + foldOp = GT_NONE; + } else { return false; @@ -9757,9 +9816,9 @@ void OptBoolsDsc::optOptimizeBoolsUpdateTrees() optReturnBlock = true; } - assert(m_foldOp != NULL && m_foldType != NULL && m_c1 != nullptr && m_c2 != nullptr); + assert(m_cmpOp != NULL && m_c1 != nullptr && m_c2 != nullptr); - GenTree* cmpOp1 = m_comp->gtNewOperNode(m_foldOp, m_foldType, m_c1, m_c2); + GenTree* cmpOp1 = m_foldOp == GT_NONE ? m_c1 : m_comp->gtNewOperNode(m_foldOp, m_foldType, m_c1, m_c2); if (m_testInfo1.isBool && m_testInfo2.isBool) { // When we 'OR'/'AND' two booleans, the result is boolean as well @@ -10047,6 +10106,68 @@ bool OptBoolsDsc::optOptimizeBoolsReturnBlock(BasicBlock* b3) foldOp = GT_OR; cmpOp = GT_LT; } + else if (m_c1->gtOper == GT_LCL_VAR && m_c2->gtOper == GT_LCL_VAR && + m_c1->AsLclVarCommon()->GetLclNum() == m_c2->AsLclVarCommon()->GetLclNum()) + { + if(((m_testInfo1.compTree->gtOper == GT_LT && m_testInfo2.compTree->gtOper == GT_EQ) || + (m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_LT)) && + it3val == 1) + { + // Case: x < 0 || x == 0 + // t1:c1<0 t2:c2==0 t3:c3==1 + // ==> true if c1<=0 + // + // Case: x == 0 || x < 0 + // t1:c1==0 t2:c2<0 t3:c3==1 + // ==> true if c1 <= 0 + cmpOp = GT_LE; + } + else if (((m_testInfo1.compTree->gtOper == GT_GT && m_testInfo2.compTree->gtOper == GT_EQ) || + (m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_GT)) && + it3val == 1) + { + // Case: x > 0 || x == 0 + // t1:c1<0 t2:c2==0 t3:c3==1 + // ==> true if c1>=0 + // + // Case: x == 0 || x > 0 + // t1:c1==0 t2:c2>0 t3:c3==1 + // ==> true if c1 >= 0 + cmpOp = GT_LE; + } + else if (((m_testInfo1.compTree->gtOper == GT_LT && m_testInfo2.compTree->gtOper == GT_NE) || + (m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_GE)) && + it3val == 0) + { + // Case: x >= 0 && x != 0 + // t1:c1<0 t2:c2==0 t3:c3==0 + // ==> true if c1>0 + // + // Case: x != 0 && x >= 0 + // t1:c1==0 t2:c2>=0 t3:c3==0 + // ==> true if c1>0 + cmpOp = GT_GT; + } + else if (((m_testInfo1.compTree->gtOper == GT_GT && m_testInfo2.compTree->gtOper == GT_NE) || + (m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_LE)) && + it3val == 0) + { + // Case: x <= 0 && x != 0 + // t1:c1<0 t2:c2==0 t3:c3==0 + // ==> true if c1<0 + // + // Case: x != 0 && x <= 0 + // t1:c1==0 t2:c2<=0 t3:c3==0 + // ==> true if c1<0 + cmpOp = GT_LT; + } + else + { + return false; + } + + foldOp = GT_NONE; + } else { // Require NOT operation for operand(s). Do Not fold. @@ -10316,6 +10437,54 @@ GenTree* OptBoolsDsc::optIsBoolComp(OptTestInfo* pOptTest) // | \--* LCL_VAR int V01 arg1 // \--* CNS_INT int 0 // +// Case 8: (x < 0 || x == 0) => x <= 0 +// * RETURN int +// \--* LE int +// +--* LCL_VAR int V00 arg0 +// \--* CNS_INT int 0 +// +// Case 9: (x == 0 || x < 0) => x <= 0 +// * RETURN int +// \--* LE int +// +--* LCL_VAR int V00 arg0 +// \--* CNS_INT int 0 +// +// Case 10: (x > 0 || x == 0) => x >= 0 +// * RETURN int +// \--* GE int +// +--* LCL_VAR int V00 arg0 +// \--* CNS_INT int 0 +// +// Case 11: (x == 0 || x > 0) => x >= 0 +// * RETURN int +// \--* GE int +// +--* LCL_VAR int V00 arg0 +// \--* CNS_INT int 0 +// +// Case 12: (x >= 0 && x != 0) => x > 0 +// * RETURN int +// \--* GT int +// +--* LCL_VAR int V00 arg0 +// \--* CNS_INT int 0 +// +// Case 13: (x != 0 && x >= 0) => x > 0 +// * RETURN int +// \--* GT int +// +--* LCL_VAR int V00 arg0 +// \--* CNS_INT int 0 +// +// Case 14: (x <= 0 && x != 0) => x < 0 +// * RETURN int +// \--* LT int +// +--* LCL_VAR int V00 arg0 +// \--* CNS_INT int 0 +// +// Case 15: (x != 0 && x <= 0) => x < 0 +// * RETURN int +// \--* LT int +// +--* LCL_VAR int V00 arg0 +// \--* CNS_INT int 0 +// // Patterns that are not optimized include (x == 1 && y == 1), (x == 1 || y == 1), // (x == 0 || y == 0) because currently their comptree is not marked as boolean expression. // When m_foldOp == GT_AND or m_cmpOp == GT_NE, both compTrees must be boolean expression diff --git a/src/tests/JIT/opt/OptimizeBools/optboolsreturn.cs b/src/tests/JIT/opt/OptimizeBools/optboolsreturn.cs index 2144be73aedca4..d88a4947255a9d 100644 --- a/src/tests/JIT/opt/OptimizeBools/optboolsreturn.cs +++ b/src/tests/JIT/opt/OptimizeBools/optboolsreturn.cs @@ -158,6 +158,53 @@ private static bool EitherNonZero(int x, int y) return x != 0 || y != 0; } + [MethodImpl(MethodImplOptions.NoInlining)] + private static bool GreaterThanOrEqualZero(int x) + { + return x == 0 || x > 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static bool GreaterThanOrEqualZeroBis(int x) + { + return x > 0 || x == 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static bool LessThanOrEqualZero(int x) + { + return x == 0 || x < 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static bool LessThanOrEqualZeroBis(int x) + { + return x < 0 || x == 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static bool GreaterThanZero(int x) + { + return x != 0 && x >= 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static bool GreaterThanZeroBis(int x) + { + return x >= 0 && x != 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static bool LessThanZero(int x) + { + return x != 0 && x <= 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static bool LessThanZeroBis(int x) + { + return x <= 0 && x != 0; + } [MethodImpl(MethodImplOptions.NoInlining)] private static bool AreBothGreatThanZero(int x, int y) { @@ -191,6 +238,94 @@ private static bool IsEitherNonZero(int x, int y) return b; } + [MethodImpl(MethodImplOptions.NoInlining)] + private static bool IsGreaterThanOrEqualZero(int x) + { + bool b = x == 0 || x > 0; + if (b) + { + Console.WriteLine("IsGreaterThanOrEqualZero true"); + } + return b; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static bool IsGreaterThanOrEqualZeroBis(int x) + { + bool b = x > 0 || x == 0; + if (b) + { + Console.WriteLine("IsGreaterThanOrEqualZeroBis true"); + } + return b; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static bool IsLessThanOrEqualZero(int x) + { + bool b = x == 0 || x < 0; + if (b) + { + Console.WriteLine("IsLessThanOrEqualZero true"); + } + return b; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static bool IsLessThanOrEqualZeroBis(int x) + { + bool b = x < 0 || x == 0; + if (b) + { + Console.WriteLine("IsLessThanOrEqualZeroBis true"); + } + return b; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static bool IsGreaterThanZero(int x) + { + bool b = x != 0 && x >= 0; + if (b) + { + Console.WriteLine("IsGreaterThanZero true"); + } + return b; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static bool IsGreaterThanZeroBis(int x) + { + bool b = x >= 0 && x != 0; + if (b) + { + Console.WriteLine("IsGreaterThanZeroBis true"); + } + return b; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static bool IsLessThanZero(int x) + { + bool b = x != 0 && x <= 0; + if (b) + { + Console.WriteLine("IsLessThanZero true"); + } + return b; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static bool IsLessThanZeroBis(int x) + { + bool b = x <= 0 && x != 0; + if (b) + { + Console.WriteLine("IsLessThanZeroBis true"); + } + return b; + } + public static int Main() { // Optimize boolean @@ -509,6 +644,150 @@ public static int Main() return 101; } + if (!GreaterThanOrEqualZero(10)) + { + Console.WriteLine("CBoolTest:GreaterThanOrEqualZero(10) failed"); + return 101; + } + + if (!GreaterThanOrEqualZero(0)) + { + Console.WriteLine("CBoolTest:GreaterThanOrEqualZero(0) failed"); + return 101; + } + + if (GreaterThanOrEqualZero(-10)) + { + Console.WriteLine("CBoolTest:GreaterThanOrEqualZero(-10) failed"); + return 101; + } + + if (!GreaterThanOrEqualZeroBis(10)) + { + Console.WriteLine("CBoolTest:GreaterThanOrEqualZeroBis(10) failed"); + return 101; + } + + if (!GreaterThanOrEqualZeroBis(0)) + { + Console.WriteLine("CBoolTest:GreaterThanOrEqualZeroBis(0) failed"); + return 101; + } + + if (GreaterThanOrEqualZeroBis(-10)) + { + Console.WriteLine("CBoolTest:GreaterThanOrEqualZeroBis(-10) failed"); + return 101; + } + + if (!GreaterThanZero(10)) + { + Console.WriteLine("CBoolTest:GreaterThanZero(10) failed"); + return 101; + } + + if (GreaterThanZero(0)) + { + Console.WriteLine("CBoolTest:GreaterThanZero(0) failed"); + return 101; + } + + if (GreaterThanZero(-10)) + { + Console.WriteLine("CBoolTest:GreaterThanZero(-10) failed"); + return 101; + } + + if (!GreaterThanZeroBis(10)) + { + Console.WriteLine("CBoolTest:GreaterThanZeroBis(10) failed"); + return 101; + } + + if (GreaterThanZeroBis(0)) + { + Console.WriteLine("CBoolTest:GreaterThanZero(0) failed"); + return 101; + } + + if (GreaterThanZeroBis(-10)) + { + Console.WriteLine("CBoolTest:GreaterThanZero(-10) failed"); + return 101; + } + + if (LessThanOrEqualZero(10)) + { + Console.WriteLine("CBoolTest:LessThanOrEqualZero(10) failed"); + return 101; + } + + if (!LessThanOrEqualZero(0)) + { + Console.WriteLine("CBoolTest:LessThanOrEqualZero(0) failed"); + return 101; + } + + if (!LessThanOrEqualZero(-10)) + { + Console.WriteLine("CBoolTest:LessThanOrEqualZero(-10) failed"); + return 101; + } + + if (LessThanOrEqualZeroBis(10)) + { + Console.WriteLine("CBoolTest:LessThanOrEqualZeroBis(10) failed"); + return 101; + } + + if (!LessThanOrEqualZeroBis(0)) + { + Console.WriteLine("CBoolTest:LessThanOrEqualZeroBis(0) failed"); + return 101; + } + + if (!LessThanOrEqualZeroBis(-10)) + { + Console.WriteLine("CBoolTest:LessThanOrEqualZeroBis(-10) failed"); + return 101; + } + + if (LessThanZero(10)) + { + Console.WriteLine("CBoolTest:LessThanZero(10) failed"); + return 101; + } + + if (LessThanZero(0)) + { + Console.WriteLine("CBoolTest:LessThanZero(0) failed"); + return 101; + } + + if (!LessThanZero(-10)) + { + Console.WriteLine("CBoolTest:LessThanZero(-10) failed"); + return 101; + } + + if (LessThanZeroBis(10)) + { + Console.WriteLine("CBoolTest:LessThanZeroBis(10) failed"); + return 101; + } + + if (LessThanZeroBis(0)) + { + Console.WriteLine("CBoolTest:LessThanZeroBis(0) failed"); + return 101; + } + + if (!LessThanZeroBis(-10)) + { + Console.WriteLine("CBoolTest:LessThanZeroBis(-10) failed"); + return 101; + } + if (IsEitherLessThanZero(45, 23)) { Console.WriteLine("CBoolTest:IsEitherLessThanZero(45, 23) failed"); @@ -575,6 +854,150 @@ public static int Main() return 101; } + if (!IsGreaterThanOrEqualZero(10)) + { + Console.WriteLine("CBoolTest:IsGreaterThanOrEqualZero(10) failed"); + return 101; + } + + if (!IsGreaterThanOrEqualZero(0)) + { + Console.WriteLine("CBoolTest:IsGreaterThanOrEqualZero(0) failed"); + return 101; + } + + if (IsGreaterThanOrEqualZero(-10)) + { + Console.WriteLine("CBoolTest:IsGreaterThanOrEqualZero(-10) failed"); + return 101; + } + + if (!IsGreaterThanOrEqualZeroBis(10)) + { + Console.WriteLine("CBoolTest:IsGreaterThanOrEqualZeroBis(10) failed"); + return 101; + } + + if (!IsGreaterThanOrEqualZeroBis(0)) + { + Console.WriteLine("CBoolTest:IsGreaterThanOrEqualZeroBis(0) failed"); + return 101; + } + + if (IsGreaterThanOrEqualZeroBis(-10)) + { + Console.WriteLine("CBoolTest:IsGreaterThanOrEqualZeroBis(-10) failed"); + return 101; + } + + if (!IsGreaterThanZero(10)) + { + Console.WriteLine("CBoolTest:IsGreaterThanZero(10) failed"); + return 101; + } + + if (IsGreaterThanZero(0)) + { + Console.WriteLine("CBoolTest:IsGreaterThanZero(0) failed"); + return 101; + } + + if (IsGreaterThanZero(-10)) + { + Console.WriteLine("CBoolTest:IsGreaterThanZero(-10) failed"); + return 101; + } + + if (!IsGreaterThanZeroBis(10)) + { + Console.WriteLine("CBoolTest:IsGreaterThanZeroBis(10) failed"); + return 101; + } + + if (IsGreaterThanZeroBis(0)) + { + Console.WriteLine("CBoolTest:IsGreaterThanZeroBis(0) failed"); + return 101; + } + + if (IsGreaterThanZeroBis(-10)) + { + Console.WriteLine("CBoolTest:IsGreaterThanZero(-10) failed"); + return 101; + } + + if (IsLessThanOrEqualZero(10)) + { + Console.WriteLine("CBoolTest:IsLessThanOrEqualZero(10) failed"); + return 101; + } + + if (!IsLessThanOrEqualZero(0)) + { + Console.WriteLine("CBoolTest:IsLessThanOrEqualZero(0) failed"); + return 101; + } + + if (!IsLessThanOrEqualZero(-10)) + { + Console.WriteLine("CBoolTest:IsLessThanOrEqualZero(-10) failed"); + return 101; + } + + if (IsLessThanOrEqualZeroBis(10)) + { + Console.WriteLine("CBoolTest:IsLessThanOrEqualZeroBis(10) failed"); + return 101; + } + + if (!IsLessThanOrEqualZeroBis(0)) + { + Console.WriteLine("CBoolTest:IsLessThanOrEqualZeroBis(0) failed"); + return 101; + } + + if (!IsLessThanOrEqualZeroBis(-10)) + { + Console.WriteLine("CBoolTest:IsLessThanOrEqualZeroBis(-10) failed"); + return 101; + } + + if (IsLessThanZero(10)) + { + Console.WriteLine("CBoolTest:IsLessThanZero(10) failed"); + return 101; + } + + if (IsLessThanZero(0)) + { + Console.WriteLine("CBoolTest:IsLessThanZero(0) failed"); + return 101; + } + + if (!IsLessThanZero(-10)) + { + Console.WriteLine("CBoolTest:IsLessThanZero(-10) failed"); + return 101; + } + + if (IsLessThanZeroBis(10)) + { + Console.WriteLine("CBoolTest:IsLessThanZeroBis(10) failed"); + return 101; + } + + if (IsLessThanZeroBis(0)) + { + Console.WriteLine("CBoolTest:IsLessThanZeroBis(0) failed"); + return 101; + } + + if (!IsLessThanZeroBis(-10)) + { + Console.WriteLine("CBoolTest:IsLessThanZeroBis(-10) failed"); + return 101; + } + if (!AreNullWithOutput(null, null)) { Console.WriteLine("CBoolTest:AreNullWithOutput(null, null) failed"); From 114adb22275b1b413dfd7e73aa96f156b24162df Mon Sep 17 00:00:00 2001 From: pedrobsaila Date: Thu, 24 Nov 2022 18:31:26 +0100 Subject: [PATCH 2/9] let's format it well --- src/coreclr/jit/optimizer.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/coreclr/jit/optimizer.cpp b/src/coreclr/jit/optimizer.cpp index 7e00187f76cbdc..2bbc58f7724c3a 100644 --- a/src/coreclr/jit/optimizer.cpp +++ b/src/coreclr/jit/optimizer.cpp @@ -9525,7 +9525,7 @@ bool OptBoolsDsc::optOptimizeBoolsCondBlock() // // Case: t1:c1==0 t2:c1<0 // So we will branch to BX if c1<=0 - cmpOp = GT_LE; + cmpOp = GT_LE; } else if ((m_testInfo1.compTree->gtOper == GT_GT && m_testInfo2.compTree->gtOper == GT_EQ) || (m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_GT)) @@ -9535,7 +9535,7 @@ bool OptBoolsDsc::optOptimizeBoolsCondBlock() // // Case: t1:c1==0 t2:c1>0 // So we will branch to BX if c1>=0 - cmpOp = GT_GE; + cmpOp = GT_GE; } else { @@ -9595,7 +9595,7 @@ bool OptBoolsDsc::optOptimizeBoolsCondBlock() // // Case: t1:c1==0 t2:c1>=0 // So we will branch to BX if c1>0 - cmpOp = GT_GT; + cmpOp = GT_GT; } else if ((m_testInfo1.compTree->gtOper == GT_GT && m_testInfo2.compTree->gtOper == GT_NE) || (m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_LE)) @@ -9605,7 +9605,7 @@ bool OptBoolsDsc::optOptimizeBoolsCondBlock() // // Case: t1:c1==0 t2:c1<=0 // So we will branch to BX if c1<0 - cmpOp = GT_LT; + cmpOp = GT_LT; } else { @@ -10109,9 +10109,9 @@ bool OptBoolsDsc::optOptimizeBoolsReturnBlock(BasicBlock* b3) else if (m_c1->gtOper == GT_LCL_VAR && m_c2->gtOper == GT_LCL_VAR && m_c1->AsLclVarCommon()->GetLclNum() == m_c2->AsLclVarCommon()->GetLclNum()) { - if(((m_testInfo1.compTree->gtOper == GT_LT && m_testInfo2.compTree->gtOper == GT_EQ) || - (m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_LT)) && - it3val == 1) + if (((m_testInfo1.compTree->gtOper == GT_LT && m_testInfo2.compTree->gtOper == GT_EQ) || + (m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_LT)) && + it3val == 1) { // Case: x < 0 || x == 0 // t1:c1<0 t2:c2==0 t3:c3==1 @@ -10165,7 +10165,7 @@ bool OptBoolsDsc::optOptimizeBoolsReturnBlock(BasicBlock* b3) { return false; } - + foldOp = GT_NONE; } else @@ -10442,13 +10442,13 @@ GenTree* OptBoolsDsc::optIsBoolComp(OptTestInfo* pOptTest) // \--* LE int // +--* LCL_VAR int V00 arg0 // \--* CNS_INT int 0 -// +// // Case 9: (x == 0 || x < 0) => x <= 0 // * RETURN int // \--* LE int // +--* LCL_VAR int V00 arg0 // \--* CNS_INT int 0 -// +// // Case 10: (x > 0 || x == 0) => x >= 0 // * RETURN int // \--* GE int @@ -10460,13 +10460,13 @@ GenTree* OptBoolsDsc::optIsBoolComp(OptTestInfo* pOptTest) // \--* GE int // +--* LCL_VAR int V00 arg0 // \--* CNS_INT int 0 -// +// // Case 12: (x >= 0 && x != 0) => x > 0 // * RETURN int // \--* GT int // +--* LCL_VAR int V00 arg0 // \--* CNS_INT int 0 -// +// // Case 13: (x != 0 && x >= 0) => x > 0 // * RETURN int // \--* GT int From 3744b08de4fdececefca8dd9f4f72670acb93ff7 Mon Sep 17 00:00:00 2001 From: pedrobsaila Date: Thu, 24 Nov 2022 21:52:16 +0100 Subject: [PATCH 3/9] authorize other ops --- src/coreclr/jit/optimizer.cpp | 279 ++++++++++++++++++---------------- 1 file changed, 148 insertions(+), 131 deletions(-) diff --git a/src/coreclr/jit/optimizer.cpp b/src/coreclr/jit/optimizer.cpp index 2bbc58f7724c3a..c96a28608ec5b9 100644 --- a/src/coreclr/jit/optimizer.cpp +++ b/src/coreclr/jit/optimizer.cpp @@ -9480,42 +9480,12 @@ bool OptBoolsDsc::optOptimizeBoolsCondBlock() foldType = TYP_I_IMPL; } - assert(m_testInfo1.compTree->OperIs(GT_EQ, GT_NE, GT_LT, GT_GE)); + assert(m_testInfo1.compTree->OperIs(GT_EQ, GT_NE, GT_LT, GT_GT, GT_GE, GT_LE)); if (m_sameTarget) { - // Both conditions must be the same - - if (m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_EQ) - { - // t1:c1==0 t2:c2==0 ==> Branch to BX if either value is 0 - // So we will branch to BX if (c1&c2)==0 - - foldOp = GT_AND; - cmpOp = GT_EQ; - } - else if (m_testInfo1.compTree->gtOper == GT_LT && m_testInfo2.compTree->gtOper == GT_LT) - { - // t1:c1<0 t2:c2<0 ==> Branch to BX if either value < 0 - // So we will branch to BX if (c1|c2)<0 - - foldOp = GT_OR; - cmpOp = GT_LT; - } - else if (m_testInfo1.compTree->gtOper == GT_GE && m_testInfo2.compTree->gtOper == GT_GE) - { - return false; - } - else if (m_testInfo1.compTree->gtOper == GT_NE && m_testInfo2.compTree->gtOper == GT_NE) - { - // t1:c1!=0 t2:c2!=0 ==> Branch to BX if either value is non-0 - // So we will branch to BX if (c1|c2)!=0 - - foldOp = GT_OR; - cmpOp = GT_NE; - } - else if (m_c1->gtOper == GT_LCL_VAR && m_c2->gtOper == GT_LCL_VAR && - m_c1->AsLclVarCommon()->GetLclNum() == m_c2->AsLclVarCommon()->GetLclNum()) + if (m_c1->gtOper == GT_LCL_VAR && m_c2->gtOper == GT_LCL_VAR && + m_c1->AsLclVarCommon()->GetLclNum() == m_c2->AsLclVarCommon()->GetLclNum()) { if ((m_testInfo1.compTree->gtOper == GT_LT && m_testInfo2.compTree->gtOper == GT_EQ) || (m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_LT)) @@ -9544,48 +9514,51 @@ bool OptBoolsDsc::optOptimizeBoolsCondBlock() foldOp = GT_NONE; } - else + else if (!m_testInfo1.testTree->AsOp()->gtOp1->IsUnsigned() && + !m_testInfo2.testTree->AsOp()->gtOp1->IsUnsigned()) { - return false; - } - } - else - { - if (m_testInfo1.compTree->gtOper == m_testInfo2.compTree->gtOper) - { - return false; - } + if (m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_EQ) + { + // t1:c1==0 t2:c2==0 ==> Branch to BX if either value is 0 + // So we will branch to BX if (c1&c2)==0 - if (m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_NE) - { - // t1:c1==0 t2:c2!=0 ==> Branch to BX if both values are non-0 - // So we will branch to BX if (c1&c2)!=0 + foldOp = GT_AND; + cmpOp = GT_EQ; + } + else if (m_testInfo1.compTree->gtOper == GT_LT && m_testInfo2.compTree->gtOper == GT_LT) + { + // t1:c1<0 t2:c2<0 ==> Branch to BX if either value < 0 + // So we will branch to BX if (c1|c2)<0 - foldOp = GT_AND; - cmpOp = GT_NE; - } - else if (m_testInfo1.compTree->gtOper == GT_LT && m_testInfo2.compTree->gtOper == GT_GE) - { - // t1:c1<0 t2:c2>=0 ==> Branch to BX if both values >= 0 - // So we will branch to BX if (c1|c2)>=0 + foldOp = GT_OR; + cmpOp = GT_LT; + } + else if (m_testInfo1.compTree->gtOper == GT_GE && m_testInfo2.compTree->gtOper == GT_GE) + { + return false; + } + else if (m_testInfo1.compTree->gtOper == GT_NE && m_testInfo2.compTree->gtOper == GT_NE) + { + // t1:c1!=0 t2:c2!=0 ==> Branch to BX if either value is non-0 + // So we will branch to BX if (c1|c2)!=0 - foldOp = GT_OR; - cmpOp = GT_GE; + foldOp = GT_OR; + cmpOp = GT_NE; + } + else + { + return false; + } } - else if (m_testInfo1.compTree->gtOper == GT_GE) + else { return false; } - else if (m_testInfo1.compTree->gtOper == GT_NE && m_testInfo2.compTree->gtOper == GT_EQ) - { - // t1:c1!=0 t2:c2==0 ==> Branch to BX if both values are 0 - // So we will branch to BX if (c1|c2)==0 - - foldOp = GT_OR; - cmpOp = GT_EQ; - } - else if (m_c1->gtOper == GT_LCL_VAR && m_c2->gtOper == GT_LCL_VAR && - m_c1->AsLclVarCommon()->GetLclNum() == m_c2->AsLclVarCommon()->GetLclNum()) + } + else + { + if (m_c1->gtOper == GT_LCL_VAR && m_c2->gtOper == GT_LCL_VAR && + m_c1->AsLclVarCommon()->GetLclNum() == m_c2->AsLclVarCommon()->GetLclNum()) { if ((m_testInfo1.compTree->gtOper == GT_LT && m_testInfo2.compTree->gtOper == GT_NE) || (m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_GE)) @@ -9614,6 +9587,42 @@ bool OptBoolsDsc::optOptimizeBoolsCondBlock() foldOp = GT_NONE; } + else if (!m_testInfo1.testTree->AsOp()->gtOp1->IsUnsigned() && + !m_testInfo2.testTree->AsOp()->gtOp1->IsUnsigned()) + { + if (m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_NE) + { + // t1:c1==0 t2:c2!=0 ==> Branch to BX if both values are non-0 + // So we will branch to BX if (c1&c2)!=0 + + foldOp = GT_AND; + cmpOp = GT_NE; + } + else if (m_testInfo1.compTree->gtOper == GT_LT && m_testInfo2.compTree->gtOper == GT_GE) + { + // t1:c1<0 t2:c2>=0 ==> Branch to BX if both values >= 0 + // So we will branch to BX if (c1|c2)>=0 + + foldOp = GT_OR; + cmpOp = GT_GE; + } + else if (m_testInfo1.compTree->gtOper == GT_GE) + { + return false; + } + else if (m_testInfo1.compTree->gtOper == GT_NE && m_testInfo2.compTree->gtOper == GT_EQ) + { + // t1:c1!=0 t2:c2==0 ==> Branch to BX if both values are 0 + // So we will branch to BX if (c1|c2)==0 + + foldOp = GT_OR; + cmpOp = GT_EQ; + } + else + { + return false; + } + } else { return false; @@ -9759,8 +9768,10 @@ Statement* OptBoolsDsc::optOptimizeBoolsChkBlkCond() // bool OptBoolsDsc::optOptimizeBoolsChkTypeCostCond() { - assert(m_testInfo1.compTree->OperIs(GT_EQ, GT_NE, GT_LT, GT_GE) && m_testInfo1.compTree->AsOp()->gtOp1 == m_c1); - assert(m_testInfo2.compTree->OperIs(GT_EQ, GT_NE, GT_LT, GT_GE) && m_testInfo2.compTree->AsOp()->gtOp1 == m_c2); + assert(m_testInfo1.compTree->OperIs(GT_EQ, GT_NE, GT_LT, GT_GT, GT_GE, GT_LE) && + m_testInfo1.compTree->AsOp()->gtOp1 == m_c1); + assert(m_testInfo2.compTree->OperIs(GT_EQ, GT_NE, GT_LT, GT_GT, GT_GE, GT_LE) && + m_testInfo2.compTree->AsOp()->gtOp1 == m_c2); // // Leave out floats where the bit-representation is more complicated @@ -10050,64 +10061,8 @@ bool OptBoolsDsc::optOptimizeBoolsReturnBlock(BasicBlock* b3) ssize_t it2val = m_testInfo2.compTree->AsOp()->gtOp2->AsIntCon()->gtIconVal; ssize_t it3val = m_t3->AsOp()->gtOp1->AsIntCon()->gtIconVal; - if ((m_testInfo1.compTree->gtOper == GT_NE && m_testInfo2.compTree->gtOper == GT_EQ) && - (it1val == 0 && it2val == 0 && it3val == 0)) - { - // Case: x == 0 && y == 0 - // t1:c1!=0 t2:c2==0 t3:c3==0 - // ==> true if (c1|c2)==0 - foldOp = GT_OR; - cmpOp = GT_EQ; - } - else if ((m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_NE) && - (it1val == 0 && it2val == 0 && it3val == 0)) - { - // Case: x == 1 && y ==1 - // t1:c1!=1 t2:c2==1 t3:c3==0 is reversed from optIsBoolComp() to: t1:c1==0 t2:c2!=0 t3:c3==0 - // ==> true if (c1&c2)!=0 - foldOp = GT_AND; - cmpOp = GT_NE; - } - else if ((m_testInfo1.compTree->gtOper == GT_LT && m_testInfo2.compTree->gtOper == GT_GE) && - (it1val == 0 && it2val == 0 && it3val == 0)) - { - // Case: x >= 0 && y >= 0 - // t1:c1<0 t2:c2>=0 t3:c3==0 - // ==> true if (c1|c2)>=0 - - foldOp = GT_OR; - cmpOp = GT_GE; - } - else if ((m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_EQ) && - (it1val == 0 && it2val == 0 && it3val == 1)) - { - // Case: x == 0 || y == 0 - // t1:c1==0 t2:c2==0 t3:c3==1 - // ==> true if (c1&c2)==0 - foldOp = GT_AND; - cmpOp = GT_EQ; - } - else if ((m_testInfo1.compTree->gtOper == GT_NE && m_testInfo2.compTree->gtOper == GT_NE) && - (it1val == 0 && it2val == 0 && it3val == 1)) - { - // Case: x == 1 || y == 1 - // t1:c1==1 t2:c2==1 t3:c3==1 is reversed from optIsBoolComp() to: t1:c1!=0 t2:c2!=0 t3:c3==1 - // ==> true if (c1|c2)!=0 - foldOp = GT_OR; - cmpOp = GT_NE; - } - else if ((m_testInfo1.compTree->gtOper == GT_LT && m_testInfo2.compTree->gtOper == GT_LT) && - (it1val == 0 && it2val == 0 && it3val == 1)) - { - // Case: x < 0 || y < 0 - // t1:c1<0 t2:c2<0 t3:c3==1 - // ==> true if (c1|c2)<0 - - foldOp = GT_OR; - cmpOp = GT_LT; - } - else if (m_c1->gtOper == GT_LCL_VAR && m_c2->gtOper == GT_LCL_VAR && - m_c1->AsLclVarCommon()->GetLclNum() == m_c2->AsLclVarCommon()->GetLclNum()) + if (m_c1->gtOper == GT_LCL_VAR && m_c2->gtOper == GT_LCL_VAR && + m_c1->AsLclVarCommon()->GetLclNum() == m_c2->AsLclVarCommon()->GetLclNum()) { if (((m_testInfo1.compTree->gtOper == GT_LT && m_testInfo2.compTree->gtOper == GT_EQ) || (m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_LT)) && @@ -10133,7 +10088,7 @@ bool OptBoolsDsc::optOptimizeBoolsReturnBlock(BasicBlock* b3) // Case: x == 0 || x > 0 // t1:c1==0 t2:c2>0 t3:c3==1 // ==> true if c1 >= 0 - cmpOp = GT_LE; + cmpOp = GT_GE; } else if (((m_testInfo1.compTree->gtOper == GT_LT && m_testInfo2.compTree->gtOper == GT_NE) || (m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_GE)) && @@ -10168,6 +10123,69 @@ bool OptBoolsDsc::optOptimizeBoolsReturnBlock(BasicBlock* b3) foldOp = GT_NONE; } + else if (!m_testInfo1.testTree->AsOp()->gtOp1->IsUnsigned() && !m_testInfo2.testTree->AsOp()->gtOp1->IsUnsigned()) + { + if ((m_testInfo1.compTree->gtOper == GT_NE && m_testInfo2.compTree->gtOper == GT_EQ) && + (it1val == 0 && it2val == 0 && it3val == 0)) + { + // Case: x == 0 && y == 0 + // t1:c1!=0 t2:c2==0 t3:c3==0 + // ==> true if (c1|c2)==0 + foldOp = GT_OR; + cmpOp = GT_EQ; + } + else if ((m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_NE) && + (it1val == 0 && it2val == 0 && it3val == 0)) + { + // Case: x == 1 && y ==1 + // t1:c1!=1 t2:c2==1 t3:c3==0 is reversed from optIsBoolComp() to: t1:c1==0 t2:c2!=0 t3:c3==0 + // ==> true if (c1&c2)!=0 + foldOp = GT_AND; + cmpOp = GT_NE; + } + else if ((m_testInfo1.compTree->gtOper == GT_LT && m_testInfo2.compTree->gtOper == GT_GE) && + (it1val == 0 && it2val == 0 && it3val == 0)) + { + // Case: x >= 0 && y >= 0 + // t1:c1<0 t2:c2>=0 t3:c3==0 + // ==> true if (c1|c2)>=0 + + foldOp = GT_OR; + cmpOp = GT_GE; + } + else if ((m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_EQ) && + (it1val == 0 && it2val == 0 && it3val == 1)) + { + // Case: x == 0 || y == 0 + // t1:c1==0 t2:c2==0 t3:c3==1 + // ==> true if (c1&c2)==0 + foldOp = GT_AND; + cmpOp = GT_EQ; + } + else if ((m_testInfo1.compTree->gtOper == GT_NE && m_testInfo2.compTree->gtOper == GT_NE) && + (it1val == 0 && it2val == 0 && it3val == 1)) + { + // Case: x == 1 || y == 1 + // t1:c1==1 t2:c2==1 t3:c3==1 is reversed from optIsBoolComp() to: t1:c1!=0 t2:c2!=0 t3:c3==1 + // ==> true if (c1|c2)!=0 + foldOp = GT_OR; + cmpOp = GT_NE; + } + else if ((m_testInfo1.compTree->gtOper == GT_LT && m_testInfo2.compTree->gtOper == GT_LT) && + (it1val == 0 && it2val == 0 && it3val == 1)) + { + // Case: x < 0 || y < 0 + // t1:c1<0 t2:c2<0 t3:c3==1 + // ==> true if (c1|c2)<0 + + foldOp = GT_OR; + cmpOp = GT_LT; + } + else + { + return false; + } + } else { // Require NOT operation for operand(s). Do Not fold. @@ -10290,9 +10308,8 @@ GenTree* OptBoolsDsc::optIsBoolComp(OptTestInfo* pOptTest) assert(pOptTest->testTree->gtOper == GT_JTRUE || pOptTest->testTree->gtOper == GT_RETURN); GenTree* cond = pOptTest->testTree->AsOp()->gtOp1; - // The condition must be "!= 0" or "== 0" or >=0 or <0 - // we don't optimize unsigned < and >= operations - if (!cond->OperIs(GT_EQ, GT_NE) && (!cond->OperIs(GT_LT, GT_GE) || cond->IsUnsigned())) + // The condition must be "!= 0" or "== 0" or >=0 or <= 0 or > 0 or < 0 + if (!cond->OperIs(GT_EQ, GT_NE, GT_LT, GT_GT, GT_GE, GT_LE)) { return nullptr; } From 0d6ff4e80439b309475249ba578cf76d53d1304c Mon Sep 17 00:00:00 2001 From: pedrobsaila Date: Thu, 24 Nov 2022 23:20:05 +0100 Subject: [PATCH 4/9] fix unsigned correctness issues --- src/coreclr/jit/optimizer.cpp | 225 ++++++++++++++++------------------ 1 file changed, 104 insertions(+), 121 deletions(-) diff --git a/src/coreclr/jit/optimizer.cpp b/src/coreclr/jit/optimizer.cpp index c96a28608ec5b9..58c7ce2ba86646 100644 --- a/src/coreclr/jit/optimizer.cpp +++ b/src/coreclr/jit/optimizer.cpp @@ -9514,41 +9514,35 @@ bool OptBoolsDsc::optOptimizeBoolsCondBlock() foldOp = GT_NONE; } - else if (!m_testInfo1.testTree->AsOp()->gtOp1->IsUnsigned() && - !m_testInfo2.testTree->AsOp()->gtOp1->IsUnsigned()) + else if (m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_EQ) { - if (m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_EQ) - { - // t1:c1==0 t2:c2==0 ==> Branch to BX if either value is 0 - // So we will branch to BX if (c1&c2)==0 + // t1:c1==0 t2:c2==0 ==> Branch to BX if either value is 0 + // So we will branch to BX if (c1&c2)==0 - foldOp = GT_AND; - cmpOp = GT_EQ; - } - else if (m_testInfo1.compTree->gtOper == GT_LT && m_testInfo2.compTree->gtOper == GT_LT) - { - // t1:c1<0 t2:c2<0 ==> Branch to BX if either value < 0 - // So we will branch to BX if (c1|c2)<0 + foldOp = GT_AND; + cmpOp = GT_EQ; + } + else if (m_testInfo1.compTree->gtOper == GT_LT && m_testInfo2.compTree->gtOper == GT_LT && + (!m_testInfo1.testTree->AsOp()->gtOp1->IsUnsigned() && + !m_testInfo2.testTree->AsOp()->gtOp1->IsUnsigned())) + { + // t1:c1<0 t2:c2<0 ==> Branch to BX if either value < 0 + // So we will branch to BX if (c1|c2)<0 - foldOp = GT_OR; - cmpOp = GT_LT; - } - else if (m_testInfo1.compTree->gtOper == GT_GE && m_testInfo2.compTree->gtOper == GT_GE) - { - return false; - } - else if (m_testInfo1.compTree->gtOper == GT_NE && m_testInfo2.compTree->gtOper == GT_NE) - { - // t1:c1!=0 t2:c2!=0 ==> Branch to BX if either value is non-0 - // So we will branch to BX if (c1|c2)!=0 + foldOp = GT_OR; + cmpOp = GT_LT; + } + else if (m_testInfo1.compTree->gtOper == GT_GE && m_testInfo2.compTree->gtOper == GT_GE) + { + return false; + } + else if (m_testInfo1.compTree->gtOper == GT_NE && m_testInfo2.compTree->gtOper == GT_NE) + { + // t1:c1!=0 t2:c2!=0 ==> Branch to BX if either value is non-0 + // So we will branch to BX if (c1|c2)!=0 - foldOp = GT_OR; - cmpOp = GT_NE; - } - else - { - return false; - } + foldOp = GT_OR; + cmpOp = GT_NE; } else { @@ -9587,41 +9581,35 @@ bool OptBoolsDsc::optOptimizeBoolsCondBlock() foldOp = GT_NONE; } - else if (!m_testInfo1.testTree->AsOp()->gtOp1->IsUnsigned() && - !m_testInfo2.testTree->AsOp()->gtOp1->IsUnsigned()) + else if (m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_NE) { - if (m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_NE) - { - // t1:c1==0 t2:c2!=0 ==> Branch to BX if both values are non-0 - // So we will branch to BX if (c1&c2)!=0 + // t1:c1==0 t2:c2!=0 ==> Branch to BX if both values are non-0 + // So we will branch to BX if (c1&c2)!=0 - foldOp = GT_AND; - cmpOp = GT_NE; - } - else if (m_testInfo1.compTree->gtOper == GT_LT && m_testInfo2.compTree->gtOper == GT_GE) - { - // t1:c1<0 t2:c2>=0 ==> Branch to BX if both values >= 0 - // So we will branch to BX if (c1|c2)>=0 + foldOp = GT_AND; + cmpOp = GT_NE; + } + else if (m_testInfo1.compTree->gtOper == GT_LT && m_testInfo2.compTree->gtOper == GT_GE && + (!m_testInfo1.testTree->AsOp()->gtOp1->IsUnsigned() && + !m_testInfo2.testTree->AsOp()->gtOp1->IsUnsigned())) + { + // t1:c1<0 t2:c2>=0 ==> Branch to BX if both values >= 0 + // So we will branch to BX if (c1|c2)>=0 - foldOp = GT_OR; - cmpOp = GT_GE; - } - else if (m_testInfo1.compTree->gtOper == GT_GE) - { - return false; - } - else if (m_testInfo1.compTree->gtOper == GT_NE && m_testInfo2.compTree->gtOper == GT_EQ) - { - // t1:c1!=0 t2:c2==0 ==> Branch to BX if both values are 0 - // So we will branch to BX if (c1|c2)==0 + foldOp = GT_OR; + cmpOp = GT_GE; + } + else if (m_testInfo1.compTree->gtOper == GT_GE) + { + return false; + } + else if (m_testInfo1.compTree->gtOper == GT_NE && m_testInfo2.compTree->gtOper == GT_EQ) + { + // t1:c1!=0 t2:c2==0 ==> Branch to BX if both values are 0 + // So we will branch to BX if (c1|c2)==0 - foldOp = GT_OR; - cmpOp = GT_EQ; - } - else - { - return false; - } + foldOp = GT_OR; + cmpOp = GT_EQ; } else { @@ -10123,68 +10111,63 @@ bool OptBoolsDsc::optOptimizeBoolsReturnBlock(BasicBlock* b3) foldOp = GT_NONE; } - else if (!m_testInfo1.testTree->AsOp()->gtOp1->IsUnsigned() && !m_testInfo2.testTree->AsOp()->gtOp1->IsUnsigned()) + else if ((m_testInfo1.compTree->gtOper == GT_NE && m_testInfo2.compTree->gtOper == GT_EQ) && + (it1val == 0 && it2val == 0 && it3val == 0)) { - if ((m_testInfo1.compTree->gtOper == GT_NE && m_testInfo2.compTree->gtOper == GT_EQ) && - (it1val == 0 && it2val == 0 && it3val == 0)) - { - // Case: x == 0 && y == 0 - // t1:c1!=0 t2:c2==0 t3:c3==0 - // ==> true if (c1|c2)==0 - foldOp = GT_OR; - cmpOp = GT_EQ; - } - else if ((m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_NE) && - (it1val == 0 && it2val == 0 && it3val == 0)) - { - // Case: x == 1 && y ==1 - // t1:c1!=1 t2:c2==1 t3:c3==0 is reversed from optIsBoolComp() to: t1:c1==0 t2:c2!=0 t3:c3==0 - // ==> true if (c1&c2)!=0 - foldOp = GT_AND; - cmpOp = GT_NE; - } - else if ((m_testInfo1.compTree->gtOper == GT_LT && m_testInfo2.compTree->gtOper == GT_GE) && - (it1val == 0 && it2val == 0 && it3val == 0)) - { - // Case: x >= 0 && y >= 0 - // t1:c1<0 t2:c2>=0 t3:c3==0 - // ==> true if (c1|c2)>=0 + // Case: x == 0 && y == 0 + // t1:c1!=0 t2:c2==0 t3:c3==0 + // ==> true if (c1|c2)==0 + foldOp = GT_OR; + cmpOp = GT_EQ; + } + else if ((m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_NE) && + (it1val == 0 && it2val == 0 && it3val == 0)) + { + // Case: x == 1 && y ==1 + // t1:c1!=1 t2:c2==1 t3:c3==0 is reversed from optIsBoolComp() to: t1:c1==0 t2:c2!=0 t3:c3==0 + // ==> true if (c1&c2)!=0 + foldOp = GT_AND; + cmpOp = GT_NE; + } + else if ((m_testInfo1.compTree->gtOper == GT_LT && m_testInfo2.compTree->gtOper == GT_GE) && + (it1val == 0 && it2val == 0 && it3val == 0) && + (!m_testInfo1.testTree->AsOp()->gtOp1->IsUnsigned() && !m_testInfo2.testTree->AsOp()->gtOp1->IsUnsigned())) + { + // Case: x >= 0 && y >= 0 + // t1:c1<0 t2:c2>=0 t3:c3==0 + // ==> true if (c1|c2)>=0 - foldOp = GT_OR; - cmpOp = GT_GE; - } - else if ((m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_EQ) && - (it1val == 0 && it2val == 0 && it3val == 1)) - { - // Case: x == 0 || y == 0 - // t1:c1==0 t2:c2==0 t3:c3==1 - // ==> true if (c1&c2)==0 - foldOp = GT_AND; - cmpOp = GT_EQ; - } - else if ((m_testInfo1.compTree->gtOper == GT_NE && m_testInfo2.compTree->gtOper == GT_NE) && - (it1val == 0 && it2val == 0 && it3val == 1)) - { - // Case: x == 1 || y == 1 - // t1:c1==1 t2:c2==1 t3:c3==1 is reversed from optIsBoolComp() to: t1:c1!=0 t2:c2!=0 t3:c3==1 - // ==> true if (c1|c2)!=0 - foldOp = GT_OR; - cmpOp = GT_NE; - } - else if ((m_testInfo1.compTree->gtOper == GT_LT && m_testInfo2.compTree->gtOper == GT_LT) && - (it1val == 0 && it2val == 0 && it3val == 1)) - { - // Case: x < 0 || y < 0 - // t1:c1<0 t2:c2<0 t3:c3==1 - // ==> true if (c1|c2)<0 + foldOp = GT_OR; + cmpOp = GT_GE; + } + else if ((m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_EQ) && + (it1val == 0 && it2val == 0 && it3val == 1)) + { + // Case: x == 0 || y == 0 + // t1:c1==0 t2:c2==0 t3:c3==1 + // ==> true if (c1&c2)==0 + foldOp = GT_AND; + cmpOp = GT_EQ; + } + else if ((m_testInfo1.compTree->gtOper == GT_NE && m_testInfo2.compTree->gtOper == GT_NE) && + (it1val == 0 && it2val == 0 && it3val == 1)) + { + // Case: x == 1 || y == 1 + // t1:c1==1 t2:c2==1 t3:c3==1 is reversed from optIsBoolComp() to: t1:c1!=0 t2:c2!=0 t3:c3==1 + // ==> true if (c1|c2)!=0 + foldOp = GT_OR; + cmpOp = GT_NE; + } + else if ((m_testInfo1.compTree->gtOper == GT_LT && m_testInfo2.compTree->gtOper == GT_LT) && + (it1val == 0 && it2val == 0 && it3val == 1) && + (!m_testInfo1.testTree->AsOp()->gtOp1->IsUnsigned() && !m_testInfo2.testTree->AsOp()->gtOp1->IsUnsigned())) + { + // Case: x < 0 || y < 0 + // t1:c1<0 t2:c2<0 t3:c3==1 + // ==> true if (c1|c2)<0 - foldOp = GT_OR; - cmpOp = GT_LT; - } - else - { - return false; - } + foldOp = GT_OR; + cmpOp = GT_LT; } else { From 02c1f5ebb8a30c6e81186d8b4557de8aebc75174 Mon Sep 17 00:00:00 2001 From: pedrobsaila Date: Thu, 24 Nov 2022 23:23:53 +0100 Subject: [PATCH 5/9] delete useless lines --- src/coreclr/jit/optimizer.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/coreclr/jit/optimizer.cpp b/src/coreclr/jit/optimizer.cpp index 58c7ce2ba86646..27030abaf4740c 100644 --- a/src/coreclr/jit/optimizer.cpp +++ b/src/coreclr/jit/optimizer.cpp @@ -9532,10 +9532,6 @@ bool OptBoolsDsc::optOptimizeBoolsCondBlock() foldOp = GT_OR; cmpOp = GT_LT; } - else if (m_testInfo1.compTree->gtOper == GT_GE && m_testInfo2.compTree->gtOper == GT_GE) - { - return false; - } else if (m_testInfo1.compTree->gtOper == GT_NE && m_testInfo2.compTree->gtOper == GT_NE) { // t1:c1!=0 t2:c2!=0 ==> Branch to BX if either value is non-0 @@ -9599,10 +9595,6 @@ bool OptBoolsDsc::optOptimizeBoolsCondBlock() foldOp = GT_OR; cmpOp = GT_GE; } - else if (m_testInfo1.compTree->gtOper == GT_GE) - { - return false; - } else if (m_testInfo1.compTree->gtOper == GT_NE && m_testInfo2.compTree->gtOper == GT_EQ) { // t1:c1!=0 t2:c2==0 ==> Branch to BX if both values are 0 From 7de185816117b8f25ddbd2706d9c5e79f62db695 Mon Sep 17 00:00:00 2001 From: pedrobsaila Date: Thu, 24 Nov 2022 23:28:54 +0100 Subject: [PATCH 6/9] update comments --- src/coreclr/jit/optimizer.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/coreclr/jit/optimizer.cpp b/src/coreclr/jit/optimizer.cpp index 27030abaf4740c..8b255c1151cb6c 100644 --- a/src/coreclr/jit/optimizer.cpp +++ b/src/coreclr/jit/optimizer.cpp @@ -10361,9 +10361,9 @@ GenTree* OptBoolsDsc::optIsBoolComp(OptTestInfo* pOptTest) // suitable phase status // // Notes: -// If the operand of GT_JTRUE/GT_RETURN node is GT_EQ/GT_NE/GT_GE/GT_LT of the form -// "if (boolVal ==/!=/>=/< 0/1)", the GT_EQ/GT_NE/GT_GE/GT_LT nodes are translated into a -// GT_EQ/GT_NE/GT_GE/GT_LT node with +// If the operand of GT_JTRUE/GT_RETURN node is GT_EQ/GT_NE/GT_GE/GT_LE/GT_GT/GT_LT of the form +// "if (boolVal ==/!=/>=/< 0/1)", the GT_EQ/GT_NE/GT_GE/GT_LE/GT_GT/GT_LT nodes are translated into a +// GT_EQ/GT_NE/GT_GE/GT_LE/GT_GT/GT_LT node with // "op1" being a boolean GT_OR/GT_AND lclVar and // "op2" the const 0/1. // For example, the folded tree for the below boolean optimization is shown below: From d33fc452793ea12bdc9f6c417683dd24f1dafea7 Mon Sep 17 00:00:00 2001 From: pedrobsaila Date: Sat, 1 Apr 2023 23:36:23 +0200 Subject: [PATCH 7/9] move code to new optimizebools.cpp --- src/coreclr/jit/optimizebools.cpp | 247 ++++++++++++++++++++++++------ 1 file changed, 204 insertions(+), 43 deletions(-) diff --git a/src/coreclr/jit/optimizebools.cpp b/src/coreclr/jit/optimizebools.cpp index af55e14a4451d4..1ed1433707f892 100644 --- a/src/coreclr/jit/optimizebools.cpp +++ b/src/coreclr/jit/optimizebools.cpp @@ -190,18 +190,41 @@ bool OptBoolsDsc::optOptimizeBoolsCondBlock() foldType = TYP_I_IMPL; } - assert(m_testInfo1.compTree->OperIs(GT_EQ, GT_NE, GT_LT, GT_GE)); + assert(m_testInfo1.compTree->OperIs(GT_EQ, GT_NE, GT_LT, GT_GT, GT_GE, GT_LE)); if (m_sameTarget) { - // Both conditions must be the same - - if (m_testInfo1.compTree->gtOper != m_testInfo2.compTree->gtOper) + if (m_c1->gtOper == GT_LCL_VAR && m_c2->gtOper == GT_LCL_VAR && + m_c1->AsLclVarCommon()->GetLclNum() == m_c2->AsLclVarCommon()->GetLclNum()) { - return false; - } + if ((m_testInfo1.compTree->gtOper == GT_LT && m_testInfo2.compTree->gtOper == GT_EQ) || + (m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_LT)) + { + // Case: t1:c1<0 t2:c1==0 + // So we will branch to BX if c1<=0 + // + // Case: t1:c1==0 t2:c1<0 + // So we will branch to BX if c1<=0 + cmpOp = GT_LE; + } + else if ((m_testInfo1.compTree->gtOper == GT_GT && m_testInfo2.compTree->gtOper == GT_EQ) || + (m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_GT)) + { + // Case: t1:c1>0 t2:c1==0 + // So we will branch to BX if c1>=0 + // + // Case: t1:c1==0 t2:c1>0 + // So we will branch to BX if c1>=0 + cmpOp = GT_GE; + } + else + { + return false; + } - if (m_testInfo1.compTree->gtOper == GT_EQ) + foldOp = GT_NONE; + } + else if (m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_EQ) { // t1:c1==0 t2:c2==0 ==> Branch to BX if either value is 0 // So we will branch to BX if (c1&c2)==0 @@ -209,7 +232,9 @@ bool OptBoolsDsc::optOptimizeBoolsCondBlock() foldOp = GT_AND; cmpOp = GT_EQ; } - else if (m_testInfo1.compTree->gtOper == GT_LT) + else if (m_testInfo1.compTree->gtOper == GT_LT && m_testInfo2.compTree->gtOper == GT_LT && + (!m_testInfo1.testTree->AsOp()->gtOp1->IsUnsigned() && + !m_testInfo2.testTree->AsOp()->gtOp1->IsUnsigned())) { // t1:c1<0 t2:c2<0 ==> Branch to BX if either value < 0 // So we will branch to BX if (c1|c2)<0 @@ -217,11 +242,7 @@ bool OptBoolsDsc::optOptimizeBoolsCondBlock() foldOp = GT_OR; cmpOp = GT_LT; } - else if (m_testInfo1.compTree->gtOper == GT_GE) - { - return false; - } - else + else if (m_testInfo1.compTree->gtOper == GT_NE && m_testInfo2.compTree->gtOper == GT_NE) { // t1:c1!=0 t2:c2!=0 ==> Branch to BX if either value is non-0 // So we will branch to BX if (c1|c2)!=0 @@ -229,15 +250,44 @@ bool OptBoolsDsc::optOptimizeBoolsCondBlock() foldOp = GT_OR; cmpOp = GT_NE; } + else + { + return false; + } } else { - if (m_testInfo1.compTree->gtOper == m_testInfo2.compTree->gtOper) + if (m_c1->gtOper == GT_LCL_VAR && m_c2->gtOper == GT_LCL_VAR && + m_c1->AsLclVarCommon()->GetLclNum() == m_c2->AsLclVarCommon()->GetLclNum()) { - return false; - } + if ((m_testInfo1.compTree->gtOper == GT_LT && m_testInfo2.compTree->gtOper == GT_NE) || + (m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_GE)) + { + // Case: t1:c1<0 t2:c1!=0 + // So we will branch to BX if c1>0 + // + // Case: t1:c1==0 t2:c1>=0 + // So we will branch to BX if c1>0 + cmpOp = GT_GT; + } + else if ((m_testInfo1.compTree->gtOper == GT_GT && m_testInfo2.compTree->gtOper == GT_NE) || + (m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_LE)) + { + // Case: t1:c1>0 t2:c1!=0 + // So we will branch to BX if c1<0 + // + // Case: t1:c1==0 t2:c1<=0 + // So we will branch to BX if c1<0 + cmpOp = GT_LT; + } + else + { + return false; + } - if (m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_NE) + foldOp = GT_NONE; + } + else if (m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_NE) { // t1:c1==0 t2:c2!=0 ==> Branch to BX if both values are non-0 // So we will branch to BX if (c1&c2)!=0 @@ -245,7 +295,9 @@ bool OptBoolsDsc::optOptimizeBoolsCondBlock() foldOp = GT_AND; cmpOp = GT_NE; } - else if (m_testInfo1.compTree->gtOper == GT_LT && m_testInfo2.compTree->gtOper == GT_GE) + else if (m_testInfo1.compTree->gtOper == GT_LT && m_testInfo2.compTree->gtOper == GT_GE && + (!m_testInfo1.testTree->AsOp()->gtOp1->IsUnsigned() && + !m_testInfo2.testTree->AsOp()->gtOp1->IsUnsigned())) { // t1:c1<0 t2:c2>=0 ==> Branch to BX if both values >= 0 // So we will branch to BX if (c1|c2)>=0 @@ -253,10 +305,6 @@ bool OptBoolsDsc::optOptimizeBoolsCondBlock() foldOp = GT_OR; cmpOp = GT_GE; } - else if (m_testInfo1.compTree->gtOper == GT_GE) - { - return false; - } else if (m_testInfo1.compTree->gtOper == GT_NE && m_testInfo2.compTree->gtOper == GT_EQ) { // t1:c1!=0 t2:c2==0 ==> Branch to BX if both values are 0 @@ -292,7 +340,7 @@ bool OptBoolsDsc::optOptimizeBoolsCondBlock() if (m_comp->verbose) { printf("Folded %sboolean conditions of " FMT_BB " and " FMT_BB " to :\n", m_c2->OperIsLeaf() ? "" : "non-leaf ", - m_b1->bbNum, m_b2->bbNum); + m_b1->bbNum, m_b2->bbNum); m_comp->gtDispStmt(s1); printf("\n"); } @@ -346,7 +394,7 @@ bool OptBoolsDsc::FindCompareChain(GenTree* condition, bool* isTestCondition) *isTestCondition = true; } else if (condOp1->OperIs(GT_AND) && isPow2(static_cast(condOp2Value)) && - condOp1->gtGetOp2()->IsIntegralConst(condOp2Value)) + condOp1->gtGetOp2()->IsIntegralConst(condOp2Value)) { // Found a EQ/NE(AND(...,n),n) which will be optimized to tbz/tbnz during lowering. *isTestCondition = true; @@ -504,7 +552,7 @@ bool OptBoolsDsc::optOptimizeCompareChainCondBlock() if (op1Cost > maxOp1Cost || op2Cost > maxOp2Cost) { JITDUMP("Skipping CompareChainCond that will evaluate conditions unconditionally at costs %d,%d\n", op1Cost, - op2Cost); + op2Cost); return false; } } @@ -554,7 +602,7 @@ bool OptBoolsDsc::optOptimizeCompareChainCondBlock() if (m_comp->verbose) { JITDUMP("\nCombined conditions " FMT_BB " and " FMT_BB " into %s chain :\n", m_b1->bbNum, m_b2->bbNum, - GenTree::OpName(chainedOper)); + GenTree::OpName(chainedOper)); m_comp->fgDumpBlock(m_b1); JITDUMP("\n"); } @@ -671,8 +719,10 @@ Statement* OptBoolsDsc::optOptimizeBoolsChkBlkCond() // bool OptBoolsDsc::optOptimizeBoolsChkTypeCostCond() { - assert(m_testInfo1.compTree->OperIs(GT_EQ, GT_NE, GT_LT, GT_GE) && m_testInfo1.compTree->AsOp()->gtOp1 == m_c1); - assert(m_testInfo2.compTree->OperIs(GT_EQ, GT_NE, GT_LT, GT_GE) && m_testInfo2.compTree->AsOp()->gtOp1 == m_c2); + assert(m_testInfo1.compTree->OperIs(GT_EQ, GT_NE, GT_LT, GT_GT, GT_GE, GT_LE) && + m_testInfo1.compTree->AsOp()->gtOp1 == m_c1); + assert(m_testInfo2.compTree->OperIs(GT_EQ, GT_NE, GT_LT, GT_GT, GT_GE, GT_LE) && + m_testInfo2.compTree->AsOp()->gtOp1 == m_c2); // // Leave out floats where the bit-representation is more complicated @@ -728,9 +778,9 @@ void OptBoolsDsc::optOptimizeBoolsUpdateTrees() optReturnBlock = true; } - assert(m_foldOp != NULL && m_foldType != NULL && m_c1 != nullptr && m_c2 != nullptr); + assert(m_cmpOp != NULL && m_c1 != nullptr && m_c2 != nullptr); - GenTree* cmpOp1 = m_comp->gtNewOperNode(m_foldOp, m_foldType, m_c1, m_c2); + GenTree* cmpOp1 = m_foldOp == GT_NONE ? m_c1 : m_comp->gtNewOperNode(m_foldOp, m_foldType, m_c1, m_c2); if (m_testInfo1.isBool && m_testInfo2.isBool) { // When we 'OR'/'AND' two booleans, the result is boolean as well @@ -962,7 +1012,69 @@ bool OptBoolsDsc::optOptimizeBoolsReturnBlock(BasicBlock* b3) ssize_t it2val = m_testInfo2.compTree->AsOp()->gtOp2->AsIntCon()->gtIconVal; ssize_t it3val = m_t3->AsOp()->gtOp1->AsIntCon()->gtIconVal; - if ((m_testInfo1.compTree->gtOper == GT_NE && m_testInfo2.compTree->gtOper == GT_EQ) && + if (m_c1->gtOper == GT_LCL_VAR && m_c2->gtOper == GT_LCL_VAR && + m_c1->AsLclVarCommon()->GetLclNum() == m_c2->AsLclVarCommon()->GetLclNum()) + { + if (((m_testInfo1.compTree->gtOper == GT_LT && m_testInfo2.compTree->gtOper == GT_EQ) || + (m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_LT)) && + it3val == 1) + { + // Case: x < 0 || x == 0 + // t1:c1<0 t2:c2==0 t3:c3==1 + // ==> true if c1<=0 + // + // Case: x == 0 || x < 0 + // t1:c1==0 t2:c2<0 t3:c3==1 + // ==> true if c1 <= 0 + cmpOp = GT_LE; + } + else if (((m_testInfo1.compTree->gtOper == GT_GT && m_testInfo2.compTree->gtOper == GT_EQ) || + (m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_GT)) && + it3val == 1) + { + // Case: x > 0 || x == 0 + // t1:c1<0 t2:c2==0 t3:c3==1 + // ==> true if c1>=0 + // + // Case: x == 0 || x > 0 + // t1:c1==0 t2:c2>0 t3:c3==1 + // ==> true if c1 >= 0 + cmpOp = GT_GE; + } + else if (((m_testInfo1.compTree->gtOper == GT_LT && m_testInfo2.compTree->gtOper == GT_NE) || + (m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_GE)) && + it3val == 0) + { + // Case: x >= 0 && x != 0 + // t1:c1<0 t2:c2==0 t3:c3==0 + // ==> true if c1>0 + // + // Case: x != 0 && x >= 0 + // t1:c1==0 t2:c2>=0 t3:c3==0 + // ==> true if c1>0 + cmpOp = GT_GT; + } + else if (((m_testInfo1.compTree->gtOper == GT_GT && m_testInfo2.compTree->gtOper == GT_NE) || + (m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_LE)) && + it3val == 0) + { + // Case: x <= 0 && x != 0 + // t1:c1<0 t2:c2==0 t3:c3==0 + // ==> true if c1<0 + // + // Case: x != 0 && x <= 0 + // t1:c1==0 t2:c2<=0 t3:c3==0 + // ==> true if c1<0 + cmpOp = GT_LT; + } + else + { + return false; + } + + foldOp = GT_NONE; + } + else if ((m_testInfo1.compTree->gtOper == GT_NE && m_testInfo2.compTree->gtOper == GT_EQ) && (it1val == 0 && it2val == 0 && it3val == 0)) { // Case: x == 0 && y == 0 @@ -972,7 +1084,7 @@ bool OptBoolsDsc::optOptimizeBoolsReturnBlock(BasicBlock* b3) cmpOp = GT_EQ; } else if ((m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_NE) && - (it1val == 0 && it2val == 0 && it3val == 0)) + (it1val == 0 && it2val == 0 && it3val == 0)) { // Case: x == 1 && y ==1 // t1:c1!=1 t2:c2==1 t3:c3==0 is reversed from optIsBoolComp() to: t1:c1==0 t2:c2!=0 t3:c3==0 @@ -981,7 +1093,8 @@ bool OptBoolsDsc::optOptimizeBoolsReturnBlock(BasicBlock* b3) cmpOp = GT_NE; } else if ((m_testInfo1.compTree->gtOper == GT_LT && m_testInfo2.compTree->gtOper == GT_GE) && - (it1val == 0 && it2val == 0 && it3val == 0)) + (it1val == 0 && it2val == 0 && it3val == 0) && + (!m_testInfo1.testTree->AsOp()->gtOp1->IsUnsigned() && !m_testInfo2.testTree->AsOp()->gtOp1->IsUnsigned())) { // Case: x >= 0 && y >= 0 // t1:c1<0 t2:c2>=0 t3:c3==0 @@ -991,7 +1104,7 @@ bool OptBoolsDsc::optOptimizeBoolsReturnBlock(BasicBlock* b3) cmpOp = GT_GE; } else if ((m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_EQ) && - (it1val == 0 && it2val == 0 && it3val == 1)) + (it1val == 0 && it2val == 0 && it3val == 1)) { // Case: x == 0 || y == 0 // t1:c1==0 t2:c2==0 t3:c3==1 @@ -1000,7 +1113,7 @@ bool OptBoolsDsc::optOptimizeBoolsReturnBlock(BasicBlock* b3) cmpOp = GT_EQ; } else if ((m_testInfo1.compTree->gtOper == GT_NE && m_testInfo2.compTree->gtOper == GT_NE) && - (it1val == 0 && it2val == 0 && it3val == 1)) + (it1val == 0 && it2val == 0 && it3val == 1)) { // Case: x == 1 || y == 1 // t1:c1==1 t2:c2==1 t3:c3==1 is reversed from optIsBoolComp() to: t1:c1!=0 t2:c2!=0 t3:c3==1 @@ -1009,7 +1122,8 @@ bool OptBoolsDsc::optOptimizeBoolsReturnBlock(BasicBlock* b3) cmpOp = GT_NE; } else if ((m_testInfo1.compTree->gtOper == GT_LT && m_testInfo2.compTree->gtOper == GT_LT) && - (it1val == 0 && it2val == 0 && it3val == 1)) + (it1val == 0 && it2val == 0 && it3val == 1) && + (!m_testInfo1.testTree->AsOp()->gtOp1->IsUnsigned() && !m_testInfo2.testTree->AsOp()->gtOp1->IsUnsigned())) { // Case: x < 0 || y < 0 // t1:c1<0 t2:c2<0 t3:c3==1 @@ -1043,7 +1157,7 @@ bool OptBoolsDsc::optOptimizeBoolsReturnBlock(BasicBlock* b3) if (m_comp->verbose) { printf("Folded %sboolean conditions of " FMT_BB ", " FMT_BB " and " FMT_BB " to :\n", - m_c2->OperIsLeaf() ? "" : "non-leaf ", m_b1->bbNum, m_b2->bbNum, m_b3->bbNum); + m_c2->OperIsLeaf() ? "" : "non-leaf ", m_b1->bbNum, m_b2->bbNum, m_b3->bbNum); m_comp->gtDispStmt(s1); printf("\n"); } @@ -1140,9 +1254,8 @@ GenTree* OptBoolsDsc::optIsBoolComp(OptTestInfo* pOptTest) assert(pOptTest->testTree->gtOper == GT_JTRUE || pOptTest->testTree->gtOper == GT_RETURN); GenTree* cond = pOptTest->testTree->AsOp()->gtOp1; - // The condition must be "!= 0" or "== 0" or >=0 or <0 - // we don't optimize unsigned < and >= operations - if (!cond->OperIs(GT_EQ, GT_NE) && (!cond->OperIs(GT_LT, GT_GE) || cond->IsUnsigned())) + // The condition must be "!= 0" or "== 0" or >=0 or <= 0 or > 0 or < 0 + if (!cond->OperIs(GT_EQ, GT_NE, GT_LT, GT_GT, GT_GE, GT_LE)) { return nullptr; } @@ -1219,9 +1332,9 @@ GenTree* OptBoolsDsc::optIsBoolComp(OptTestInfo* pOptTest) // suitable phase status // // Notes: -// If the operand of GT_JTRUE/GT_RETURN node is GT_EQ/GT_NE/GT_GE/GT_LT of the form -// "if (boolVal ==/!=/>=/< 0/1)", the GT_EQ/GT_NE/GT_GE/GT_LT nodes are translated into a -// GT_EQ/GT_NE/GT_GE/GT_LT node with +// If the operand of GT_JTRUE/GT_RETURN node is GT_EQ/GT_NE/GT_GE/GT_LE/GT_GT/GT_LT of the form +// "if (boolVal ==/!=/>=/< 0/1)", the GT_EQ/GT_NE/GT_GE/GT_LE/GT_GT/GT_LT nodes are translated into a +// GT_EQ/GT_NE/GT_GE/GT_LE/GT_GT/GT_LT node with // "op1" being a boolean GT_OR/GT_AND lclVar and // "op2" the const 0/1. // For example, the folded tree for the below boolean optimization is shown below: @@ -1287,6 +1400,54 @@ GenTree* OptBoolsDsc::optIsBoolComp(OptTestInfo* pOptTest) // | \--* LCL_VAR int V01 arg1 // \--* CNS_INT int 0 // +// Case 8: (x < 0 || x == 0) => x <= 0 +// * RETURN int +// \--* LE int +// +--* LCL_VAR int V00 arg0 +// \--* CNS_INT int 0 +// +// Case 9: (x == 0 || x < 0) => x <= 0 +// * RETURN int +// \--* LE int +// +--* LCL_VAR int V00 arg0 +// \--* CNS_INT int 0 +// +// Case 10: (x > 0 || x == 0) => x >= 0 +// * RETURN int +// \--* GE int +// +--* LCL_VAR int V00 arg0 +// \--* CNS_INT int 0 +// +// Case 11: (x == 0 || x > 0) => x >= 0 +// * RETURN int +// \--* GE int +// +--* LCL_VAR int V00 arg0 +// \--* CNS_INT int 0 +// +// Case 12: (x >= 0 && x != 0) => x > 0 +// * RETURN int +// \--* GT int +// +--* LCL_VAR int V00 arg0 +// \--* CNS_INT int 0 +// +// Case 13: (x != 0 && x >= 0) => x > 0 +// * RETURN int +// \--* GT int +// +--* LCL_VAR int V00 arg0 +// \--* CNS_INT int 0 +// +// Case 14: (x <= 0 && x != 0) => x < 0 +// * RETURN int +// \--* LT int +// +--* LCL_VAR int V00 arg0 +// \--* CNS_INT int 0 +// +// Case 15: (x != 0 && x <= 0) => x < 0 +// * RETURN int +// \--* LT int +// +--* LCL_VAR int V00 arg0 +// \--* CNS_INT int 0 +// // Patterns that are not optimized include (x == 1 && y == 1), (x == 1 || y == 1), // (x == 0 || y == 0) because currently their comptree is not marked as boolean expression. // When m_foldOp == GT_AND or m_cmpOp == GT_NE, both compTrees must be boolean expression From 1de7200e6b34fdffe8a91c5d5f8fb231cf97a3ef Mon Sep 17 00:00:00 2001 From: pedrobsaila Date: Sat, 1 Apr 2023 23:42:58 +0200 Subject: [PATCH 8/9] fix spacing --- src/coreclr/jit/optimizebools.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/coreclr/jit/optimizebools.cpp b/src/coreclr/jit/optimizebools.cpp index 1ed1433707f892..54fed2ddce756f 100644 --- a/src/coreclr/jit/optimizebools.cpp +++ b/src/coreclr/jit/optimizebools.cpp @@ -340,7 +340,7 @@ bool OptBoolsDsc::optOptimizeBoolsCondBlock() if (m_comp->verbose) { printf("Folded %sboolean conditions of " FMT_BB " and " FMT_BB " to :\n", m_c2->OperIsLeaf() ? "" : "non-leaf ", - m_b1->bbNum, m_b2->bbNum); + m_b1->bbNum, m_b2->bbNum); m_comp->gtDispStmt(s1); printf("\n"); } @@ -394,7 +394,7 @@ bool OptBoolsDsc::FindCompareChain(GenTree* condition, bool* isTestCondition) *isTestCondition = true; } else if (condOp1->OperIs(GT_AND) && isPow2(static_cast(condOp2Value)) && - condOp1->gtGetOp2()->IsIntegralConst(condOp2Value)) + condOp1->gtGetOp2()->IsIntegralConst(condOp2Value)) { // Found a EQ/NE(AND(...,n),n) which will be optimized to tbz/tbnz during lowering. *isTestCondition = true; @@ -552,7 +552,7 @@ bool OptBoolsDsc::optOptimizeCompareChainCondBlock() if (op1Cost > maxOp1Cost || op2Cost > maxOp2Cost) { JITDUMP("Skipping CompareChainCond that will evaluate conditions unconditionally at costs %d,%d\n", op1Cost, - op2Cost); + op2Cost); return false; } } @@ -602,7 +602,7 @@ bool OptBoolsDsc::optOptimizeCompareChainCondBlock() if (m_comp->verbose) { JITDUMP("\nCombined conditions " FMT_BB " and " FMT_BB " into %s chain :\n", m_b1->bbNum, m_b2->bbNum, - GenTree::OpName(chainedOper)); + GenTree::OpName(chainedOper)); m_comp->fgDumpBlock(m_b1); JITDUMP("\n"); } @@ -1075,7 +1075,7 @@ bool OptBoolsDsc::optOptimizeBoolsReturnBlock(BasicBlock* b3) foldOp = GT_NONE; } else if ((m_testInfo1.compTree->gtOper == GT_NE && m_testInfo2.compTree->gtOper == GT_EQ) && - (it1val == 0 && it2val == 0 && it3val == 0)) + (it1val == 0 && it2val == 0 && it3val == 0)) { // Case: x == 0 && y == 0 // t1:c1!=0 t2:c2==0 t3:c3==0 @@ -1084,7 +1084,7 @@ bool OptBoolsDsc::optOptimizeBoolsReturnBlock(BasicBlock* b3) cmpOp = GT_EQ; } else if ((m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_NE) && - (it1val == 0 && it2val == 0 && it3val == 0)) + (it1val == 0 && it2val == 0 && it3val == 0)) { // Case: x == 1 && y ==1 // t1:c1!=1 t2:c2==1 t3:c3==0 is reversed from optIsBoolComp() to: t1:c1==0 t2:c2!=0 t3:c3==0 @@ -1093,8 +1093,8 @@ bool OptBoolsDsc::optOptimizeBoolsReturnBlock(BasicBlock* b3) cmpOp = GT_NE; } else if ((m_testInfo1.compTree->gtOper == GT_LT && m_testInfo2.compTree->gtOper == GT_GE) && - (it1val == 0 && it2val == 0 && it3val == 0) && - (!m_testInfo1.testTree->AsOp()->gtOp1->IsUnsigned() && !m_testInfo2.testTree->AsOp()->gtOp1->IsUnsigned())) + (it1val == 0 && it2val == 0 && it3val == 0) && + (!m_testInfo1.testTree->AsOp()->gtOp1->IsUnsigned() && !m_testInfo2.testTree->AsOp()->gtOp1->IsUnsigned())) { // Case: x >= 0 && y >= 0 // t1:c1<0 t2:c2>=0 t3:c3==0 @@ -1104,7 +1104,7 @@ bool OptBoolsDsc::optOptimizeBoolsReturnBlock(BasicBlock* b3) cmpOp = GT_GE; } else if ((m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_EQ) && - (it1val == 0 && it2val == 0 && it3val == 1)) + (it1val == 0 && it2val == 0 && it3val == 1)) { // Case: x == 0 || y == 0 // t1:c1==0 t2:c2==0 t3:c3==1 @@ -1113,7 +1113,7 @@ bool OptBoolsDsc::optOptimizeBoolsReturnBlock(BasicBlock* b3) cmpOp = GT_EQ; } else if ((m_testInfo1.compTree->gtOper == GT_NE && m_testInfo2.compTree->gtOper == GT_NE) && - (it1val == 0 && it2val == 0 && it3val == 1)) + (it1val == 0 && it2val == 0 && it3val == 1)) { // Case: x == 1 || y == 1 // t1:c1==1 t2:c2==1 t3:c3==1 is reversed from optIsBoolComp() to: t1:c1!=0 t2:c2!=0 t3:c3==1 @@ -1122,8 +1122,8 @@ bool OptBoolsDsc::optOptimizeBoolsReturnBlock(BasicBlock* b3) cmpOp = GT_NE; } else if ((m_testInfo1.compTree->gtOper == GT_LT && m_testInfo2.compTree->gtOper == GT_LT) && - (it1val == 0 && it2val == 0 && it3val == 1) && - (!m_testInfo1.testTree->AsOp()->gtOp1->IsUnsigned() && !m_testInfo2.testTree->AsOp()->gtOp1->IsUnsigned())) + (it1val == 0 && it2val == 0 && it3val == 1) && + (!m_testInfo1.testTree->AsOp()->gtOp1->IsUnsigned() && !m_testInfo2.testTree->AsOp()->gtOp1->IsUnsigned())) { // Case: x < 0 || y < 0 // t1:c1<0 t2:c2<0 t3:c3==1 @@ -1157,7 +1157,7 @@ bool OptBoolsDsc::optOptimizeBoolsReturnBlock(BasicBlock* b3) if (m_comp->verbose) { printf("Folded %sboolean conditions of " FMT_BB ", " FMT_BB " and " FMT_BB " to :\n", - m_c2->OperIsLeaf() ? "" : "non-leaf ", m_b1->bbNum, m_b2->bbNum, m_b3->bbNum); + m_c2->OperIsLeaf() ? "" : "non-leaf ", m_b1->bbNum, m_b2->bbNum, m_b3->bbNum); m_comp->gtDispStmt(s1); printf("\n"); } From 512ce9b52cbbcdc19d605ef244021af61661543e Mon Sep 17 00:00:00 2001 From: pedrobsaila Date: Sun, 2 Apr 2023 00:07:48 +0200 Subject: [PATCH 9/9] format file --- src/coreclr/jit/optimizebools.cpp | 32 +++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/coreclr/jit/optimizebools.cpp b/src/coreclr/jit/optimizebools.cpp index 54fed2ddce756f..24c09679c05630 100644 --- a/src/coreclr/jit/optimizebools.cpp +++ b/src/coreclr/jit/optimizebools.cpp @@ -208,7 +208,7 @@ bool OptBoolsDsc::optOptimizeBoolsCondBlock() cmpOp = GT_LE; } else if ((m_testInfo1.compTree->gtOper == GT_GT && m_testInfo2.compTree->gtOper == GT_EQ) || - (m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_GT)) + (m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_GT)) { // Case: t1:c1>0 t2:c1==0 // So we will branch to BX if c1>=0 @@ -233,8 +233,8 @@ bool OptBoolsDsc::optOptimizeBoolsCondBlock() cmpOp = GT_EQ; } else if (m_testInfo1.compTree->gtOper == GT_LT && m_testInfo2.compTree->gtOper == GT_LT && - (!m_testInfo1.testTree->AsOp()->gtOp1->IsUnsigned() && - !m_testInfo2.testTree->AsOp()->gtOp1->IsUnsigned())) + (!m_testInfo1.testTree->AsOp()->gtOp1->IsUnsigned() && + !m_testInfo2.testTree->AsOp()->gtOp1->IsUnsigned())) { // t1:c1<0 t2:c2<0 ==> Branch to BX if either value < 0 // So we will branch to BX if (c1|c2)<0 @@ -271,7 +271,7 @@ bool OptBoolsDsc::optOptimizeBoolsCondBlock() cmpOp = GT_GT; } else if ((m_testInfo1.compTree->gtOper == GT_GT && m_testInfo2.compTree->gtOper == GT_NE) || - (m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_LE)) + (m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_LE)) { // Case: t1:c1>0 t2:c1!=0 // So we will branch to BX if c1<0 @@ -296,8 +296,8 @@ bool OptBoolsDsc::optOptimizeBoolsCondBlock() cmpOp = GT_NE; } else if (m_testInfo1.compTree->gtOper == GT_LT && m_testInfo2.compTree->gtOper == GT_GE && - (!m_testInfo1.testTree->AsOp()->gtOp1->IsUnsigned() && - !m_testInfo2.testTree->AsOp()->gtOp1->IsUnsigned())) + (!m_testInfo1.testTree->AsOp()->gtOp1->IsUnsigned() && + !m_testInfo2.testTree->AsOp()->gtOp1->IsUnsigned())) { // t1:c1<0 t2:c2>=0 ==> Branch to BX if both values >= 0 // So we will branch to BX if (c1|c2)>=0 @@ -720,9 +720,9 @@ Statement* OptBoolsDsc::optOptimizeBoolsChkBlkCond() bool OptBoolsDsc::optOptimizeBoolsChkTypeCostCond() { assert(m_testInfo1.compTree->OperIs(GT_EQ, GT_NE, GT_LT, GT_GT, GT_GE, GT_LE) && - m_testInfo1.compTree->AsOp()->gtOp1 == m_c1); + m_testInfo1.compTree->AsOp()->gtOp1 == m_c1); assert(m_testInfo2.compTree->OperIs(GT_EQ, GT_NE, GT_LT, GT_GT, GT_GE, GT_LE) && - m_testInfo2.compTree->AsOp()->gtOp1 == m_c2); + m_testInfo2.compTree->AsOp()->gtOp1 == m_c2); // // Leave out floats where the bit-representation is more complicated @@ -1016,7 +1016,7 @@ bool OptBoolsDsc::optOptimizeBoolsReturnBlock(BasicBlock* b3) m_c1->AsLclVarCommon()->GetLclNum() == m_c2->AsLclVarCommon()->GetLclNum()) { if (((m_testInfo1.compTree->gtOper == GT_LT && m_testInfo2.compTree->gtOper == GT_EQ) || - (m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_LT)) && + (m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_LT)) && it3val == 1) { // Case: x < 0 || x == 0 @@ -1029,8 +1029,8 @@ bool OptBoolsDsc::optOptimizeBoolsReturnBlock(BasicBlock* b3) cmpOp = GT_LE; } else if (((m_testInfo1.compTree->gtOper == GT_GT && m_testInfo2.compTree->gtOper == GT_EQ) || - (m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_GT)) && - it3val == 1) + (m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_GT)) && + it3val == 1) { // Case: x > 0 || x == 0 // t1:c1<0 t2:c2==0 t3:c3==1 @@ -1040,10 +1040,10 @@ bool OptBoolsDsc::optOptimizeBoolsReturnBlock(BasicBlock* b3) // t1:c1==0 t2:c2>0 t3:c3==1 // ==> true if c1 >= 0 cmpOp = GT_GE; - } + } else if (((m_testInfo1.compTree->gtOper == GT_LT && m_testInfo2.compTree->gtOper == GT_NE) || - (m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_GE)) && - it3val == 0) + (m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_GE)) && + it3val == 0) { // Case: x >= 0 && x != 0 // t1:c1<0 t2:c2==0 t3:c3==0 @@ -1055,8 +1055,8 @@ bool OptBoolsDsc::optOptimizeBoolsReturnBlock(BasicBlock* b3) cmpOp = GT_GT; } else if (((m_testInfo1.compTree->gtOper == GT_GT && m_testInfo2.compTree->gtOper == GT_NE) || - (m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_LE)) && - it3val == 0) + (m_testInfo1.compTree->gtOper == GT_EQ && m_testInfo2.compTree->gtOper == GT_LE)) && + it3val == 0) { // Case: x <= 0 && x != 0 // t1:c1<0 t2:c2==0 t3:c3==0