fuse < and > with = when applicable (#78786)
authorBadre BSAILA <54767641+pedrobsaila@users.noreply.github.com>
Sat, 10 Jun 2023 12:04:54 +0000 (14:04 +0200)
committerGitHub <noreply@github.com>
Sat, 10 Jun 2023 12:04:54 +0000 (14:04 +0200)
src/coreclr/jit/optimizebools.cpp
src/tests/JIT/opt/OptimizeBools/optboolsreturn.cs

index ef10945..043d4ac 100644 (file)
@@ -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
@@ -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,8 +1012,70 @@ 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))
+    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
         //      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
@@ -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
@@ -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
index a3c1b7c..93dd6a0 100644 (file)
@@ -160,6 +160,53 @@ public class CBoolTest
     }
 
     [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)
     {
         bool b = x >= 0 && y >= 0;
@@ -192,6 +239,94 @@ public class CBoolTest
         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;
+    }
+
     [Fact]
     public static int TestEntryPoint()
     {
@@ -511,6 +646,150 @@ public class CBoolTest
             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");
@@ -577,6 +856,150 @@ public class CBoolTest
             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");