--- old/src/hotspot/share/opto/cfgnode.cpp 2018-10-01 11:16:30.667855851 +0200 +++ new/src/hotspot/share/opto/cfgnode.cpp 2018-10-01 11:16:30.471858113 +0200 @@ -714,10 +714,126 @@ } } + if (can_reshape) { + modified |= optimize_trichotomy(phase->is_IterGVN()); + } + return modified ? this : NULL; } - +//------------------------------optimize_trichotomy-------------------------- +// Optimize nested comparisons of the following kind: +// +// int compare(int a, int b) { +// return (a < b) ? -1 : (a == b) ? 0 : 1; +// } +// +// Shape 1: +// if (compare(a, b) == 1) { ... } -> if (a > b) { ... } +// +// Shape 2: +// if (compare(a, b) == 0) { ... } -> if (a == b) { ... } +// +// Above code leads to the following IR shapes where both Ifs compare the +// same value and two out of three region inputs idx1 and idx2 map to +// the same value and control flow. +// +// (1) If (2) If +// / \ / \ +// Proj Proj Proj Proj +// | \ | \ +// | If | If If +// | / \ | / \ / \ +// | Proj Proj | Proj Proj ==> Proj Proj +// | / / \ | / | / +// Region / \ | / | / +// \ / \ | / | / +// Region Region Region +// +// The method returns true if 'this' is modified and false otherwise. +bool RegionNode::optimize_trichotomy(PhaseIterGVN* igvn) { + int idx1 = 1, idx2 = 2; + Node* region = NULL; + if (req() == 3 && in(1) != NULL && in(2) != NULL) { + // Shape 1: Check if one of the inputs is a region that merges two control + // inputs and has no other users (especially no Phi users). + region = in(1)->isa_Region() ? in(1) : in(2)->isa_Region(); + if (region == NULL || region->outcnt() != 2 || region->req() != 3) { + return false; // No suitable region input found + } + } else if (req() == 4) { + // Shape 2: Check if two control inputs map to the same value of the unique phi + // user and treat these as if they would come from another region (shape (1)). + PhiNode* phi = has_unique_phi(); + if (phi == NULL) { + return false; // No unique phi user + } + if (phi->in(idx1) != phi->in(idx2)) { + idx2 = 3; + if (phi->in(idx1) != phi->in(idx2)) { + idx1 = 2; + if (phi->in(idx1) != phi->in(idx2)) { + return false; // No equal phi inputs found + } + } + } + assert(phi->in(idx1) == phi->in(idx2), "must be"); // Region is merging same value + region = this; + } + if (region == NULL || region->in(idx1) == NULL || region->in(idx2) == NULL) { + return false; // Region does not merge two control inputs + } + // At this point we know that region->in(idx1) and region->(idx2) map to the same + // value and control flow. Now search for ifs that feed into these region inputs. + ProjNode* proj1 = region->in(idx1)->isa_Proj(); + ProjNode* proj2 = region->in(idx2)->isa_Proj(); + if (proj1 == NULL || proj1->outcnt() != 1 || + proj2 == NULL || proj2->outcnt() != 1) { + return false; // No projection inputs with region as unique user found + } + IfNode* iff1 = proj1->in(0)->isa_If(); + IfNode* iff2 = proj2->in(0)->isa_If(); + if (iff1 == NULL || iff1->outcnt() != 2 || + iff2 == NULL || iff2->outcnt() != 2) { + return false; // No ifs found + } + if (iff1 == iff2) { + igvn->replace_input_of(region, idx1, iff1->in(0)); + igvn->replace_input_of(region, idx2, igvn->C->top()); + return (region == this); // Remove useless if (both projections map to the same control/value) + } + BoolNode* bol1 = iff1->in(1)->isa_Bool(); + BoolNode* bol2 = iff2->in(1)->isa_Bool(); + if (bol1 == NULL || bol2 == NULL || bol1->in(1) != bol2->in(1)) { + return false; // Ifs are not comparing the same value + } + proj1 = proj1->other_if_proj(); + proj2 = proj2->other_if_proj(); + if (!((proj1->unique_ctrl_out() == iff2 && + proj2->unique_ctrl_out() == this) || + (proj2->unique_ctrl_out() == iff1 && + proj1->unique_ctrl_out() == this))) { + return false; // Ifs are not connected through other projs + } + // Found 'iff -> proj -> iff -> proj -> this' shape where all other projs are merged + // through 'region' and map to the same value. Merge the boolean tests and replace + // the ifs by a single comparison. + BoolTest test1 = (proj1->_con == 1) ? bol1->_test : bol1->_test.negate(); + BoolTest test2 = (proj2->_con == 1) ? bol2->_test : bol2->_test.negate(); + BoolTest::mask res = test1.merge(test2); + // Adjust iff1 to always pass (only iff2 will remain) + igvn->replace_input_of(iff1, 1, igvn->intcon(proj1->_con)); + if (res == BoolTest::never) { + // Merged test is always false, adjust iff2 to always fail + igvn->replace_input_of(iff2, 1, igvn->intcon(1 - proj2->_con)); + } else { + // Replace bool input of iff2 with merged test + assert(res != BoolTest::illegal, "Unexpected bool result %d", res); + BoolNode* new_bol = new BoolNode(bol2->in(1), res); + igvn->replace_input_of(iff2, 1, igvn->transform((proj2->_con == 1) ? new_bol : new_bol->negate(igvn))); + } + return false; +} const RegMask &RegionNode::out_RegMask() const { return RegMask::Empty; --- old/src/hotspot/share/opto/cfgnode.hpp 2018-10-01 11:16:31.155850216 +0200 +++ new/src/hotspot/share/opto/cfgnode.hpp 2018-10-01 11:16:30.955852526 +0200 @@ -96,6 +96,7 @@ virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); virtual const RegMask &out_RegMask() const; bool try_clean_mem_phi(PhaseGVN *phase); + bool optimize_trichotomy(PhaseIterGVN* igvn); }; //------------------------------JProjNode-------------------------------------- --- old/src/hotspot/share/opto/subnode.cpp 2018-10-01 11:16:31.623844813 +0200 +++ new/src/hotspot/share/opto/subnode.cpp 2018-10-01 11:16:31.427847076 +0200 @@ -1252,6 +1252,24 @@ st->print("%s", msg[_test]); } +// Returns the logical AND of two tests (or 'never' if both tests can never be true). +// For example, a test for 'le' followed by a test for 'lt' is equivalent with 'lt'. +BoolTest::mask BoolTest::merge(BoolTest other) const { + const mask res[illegal+1][illegal+1] = { + // eq, gt, of, lt, ne, le, nof, ge, never, illegal + {eq, never, illegal, never, never, eq, illegal, eq, never, illegal}, // eq + {never, gt, illegal, never, gt, never, illegal, gt, never, illegal}, // gt + {illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal, never, illegal}, // of + {never, never, illegal, lt, lt, lt, illegal, never, never, illegal}, // lt + {never, gt, illegal, lt, ne, lt, illegal, gt, never, illegal}, // ne + {eq, never, illegal, lt, lt, le, illegal, eq, never, illegal}, // le + {illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal, never, illegal}, // nof + {eq, gt, illegal, never, gt, eq, illegal, ge, never, illegal}, // ge + {never, never, never, never, never, never, never, never, never, illegal}, // never + {illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal}}; // illegal + return res[_test][other._test]; +} + //============================================================================= uint BoolNode::hash() const { return (Node::hash() << 3)|(_test._test+1); } uint BoolNode::size_of() const { return sizeof(BoolNode); } --- old/src/hotspot/share/opto/subnode.hpp 2018-10-01 11:16:32.083839503 +0200 +++ new/src/hotspot/share/opto/subnode.hpp 2018-10-01 11:16:31.891841719 +0200 @@ -280,7 +280,7 @@ // We pick the values as 3 bits; the low order 2 bits we compare against the // condition codes, the high bit flips the sense of the result. struct BoolTest { - enum mask { eq = 0, ne = 4, le = 5, ge = 7, lt = 3, gt = 1, overflow = 2, no_overflow = 6, illegal = 8 }; + enum mask { eq = 0, ne = 4, le = 5, ge = 7, lt = 3, gt = 1, overflow = 2, no_overflow = 6, never = 8, illegal = 9 }; mask _test; BoolTest( mask btm ) : _test(btm) {} const Type *cc2logical( const Type *CC ) const; @@ -293,6 +293,7 @@ bool is_less( ) const { return _test == BoolTest::lt || _test == BoolTest::le; } bool is_greater( ) const { return _test == BoolTest::gt || _test == BoolTest::ge; } void dump_on(outputStream *st) const; + mask merge(BoolTest other) const; }; //------------------------------BoolNode--------------------------------------- --- /dev/null 2018-10-01 08:15:51.125839210 +0200 +++ new/test/hotspot/jtreg/compiler/codegen/TestTrichotomyExpressions.java 2018-10-01 11:16:32.363836271 +0200 @@ -0,0 +1,645 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8210215 + * @summary Test that C2 correctly optimizes trichotomy expressions. + * @library /test/lib + * @run main/othervm -XX:-TieredCompilation -Xbatch + * -XX:CompileCommand=dontinline,compiler.codegen.TestTrichotomyExpressions::test* + * compiler.codegen.TestTrichotomyExpressions + * @run main/othervm -XX:-TieredCompilation -Xcomp + * -XX:CompileCommand=dontinline,compiler.codegen.TestTrichotomyExpressions::test* + * compiler.codegen.TestTrichotomyExpressions + */ + +package compiler.codegen; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.reflect.Method; + +import jdk.test.lib.Asserts; + +enum Operation { SMALLER, SMALLER_EQUAL, EQUAL, GREATER_EQUAL, GREATER, ALWAYS_FALSE } + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +@interface Test { + Operation op(); +} + +public class TestTrichotomyExpressions { + + public static int compare1(int a, int b) { + return (a < b) ? -1 : (a == b) ? 0 : 1; + } + + public static int compare2(int a, int b) { + return (a < b) ? -1 : (a <= b) ? 0 : 1; + } + + public static int compare3(int a, int b) { + return (a < b) ? -1 : (a > b) ? 1 : 0; + } + + public static int compare4(int a, int b) { + return (a > b) ? 1 : (a < b) ? -1 : 0; + } + + public static int compare5(int a, int b) { + return (a > b) ? 1 : (a == b) ? 0 : -1; + } + + public static int compare6(int a, int b) { + return (a > b) ? 1 : (a >= b) ? 0 : -1; + } + + public static int compare7(int a, int b) { + return (a == b) ? 0 : (a < b) ? -1 : 1; + } + + public static int compare8(int a, int b) { + return (a == b) ? 0 : (a <= b) ? -1 : 1; + } + + public static int compare9(int a, int b) { + return (a == b) ? 0 : (a > b) ? 1 : -1; + } + + public static int compare10(int a, int b) { + return (a == b) ? 0 : (a >= b) ? 1 : -1; + } + + public static int compare11(int a, int b) { + return (a >= b) ? 1 : (a > b) ? 2 : -1; + } + + public static int compare12(int a, int b) { + return (a <= b) ? 1 : (a < b) ? 2 : -1; + } + + public static int compare13(int a, int b) { + return (a == b) ? 1 : (a == b) ? 2 : -1; + } + + public static int compare14(int a, int b) { + return (a != b) ? 1 : (a < b) ? 2 : -1; + } + + + + @Test(op = Operation.SMALLER) + public static boolean testSmaller1(int a, int b) { + return compare1(a, b) == -1; + } + + @Test(op = Operation.SMALLER) + public static boolean testSmaller2(int a, int b) { + return compare1(a, b) < 0; + } + + @Test(op = Operation.SMALLER) + public static boolean testSmaller3(int a, int b) { + return compare1(a, b) <= -1; + } + + @Test(op = Operation.SMALLER) + public static boolean testSmaller4(int a, int b) { + return compare2(a, b) == -1; + } + + @Test(op = Operation.SMALLER) + public static boolean testSmaller5(int a, int b) { + return compare2(a, b) < 0; + } + + @Test(op = Operation.SMALLER) + public static boolean testSmaller6(int a, int b) { + return compare2(a, b) <= -1; + } + + @Test(op = Operation.SMALLER) + public static boolean testSmaller7(int a, int b) { + return compare3(a, b) == -1; + } + + @Test(op = Operation.SMALLER) + public static boolean testSmaller8(int a, int b) { + return compare3(a, b) < 0; + } + + @Test(op = Operation.SMALLER) + public static boolean testSmaller9(int a, int b) { + return compare3(a, b) <= -1; + } + + @Test(op = Operation.SMALLER) + public static boolean testSmaller10(int a, int b) { + return compare4(a, b) == -1; + } + + @Test(op = Operation.SMALLER) + public static boolean testSmaller11(int a, int b) { + return compare4(a, b) < 0; + } + + @Test(op = Operation.SMALLER) + public static boolean testSmaller12(int a, int b) { + return compare4(a, b) <= -1; + } + + @Test(op = Operation.SMALLER) + public static boolean testSmaller13(int a, int b) { + return compare5(a, b) == -1; + } + + @Test(op = Operation.SMALLER) + public static boolean testSmaller14(int a, int b) { + return compare5(a, b) < 0; + } + + @Test(op = Operation.SMALLER) + public static boolean testSmaller15(int a, int b) { + return compare5(a, b) <= -1; + } + + @Test(op = Operation.SMALLER) + public static boolean testSmaller16(int a, int b) { + return compare6(a, b) == -1; + } + + @Test(op = Operation.SMALLER) + public static boolean testSmaller17(int a, int b) { + return compare6(a, b) < 0; + } + + @Test(op = Operation.SMALLER) + public static boolean testSmaller18(int a, int b) { + return compare6(a, b) <= -1; + } + + @Test(op = Operation.SMALLER) + public static boolean testSmaller19(int a, int b) { + return compare7(a, b) == -1; + } + + @Test(op = Operation.SMALLER) + public static boolean testSmaller20(int a, int b) { + return compare7(a, b) < 0; + } + + @Test(op = Operation.SMALLER) + public static boolean testSmaller21(int a, int b) { + return compare7(a, b) <= -1; + } + + @Test(op = Operation.SMALLER) + public static boolean testSmaller22(int a, int b) { + return compare8(a, b) == -1; + } + + @Test(op = Operation.SMALLER) + public static boolean testSmaller23(int a, int b) { + return compare8(a, b) < 0; + } + + @Test(op = Operation.SMALLER) + public static boolean testSmaller24(int a, int b) { + return compare8(a, b) <= -1; + } + + @Test(op = Operation.SMALLER) + public static boolean testSmaller25(int a, int b) { + return compare9(a, b) == -1; + } + + @Test(op = Operation.SMALLER) + public static boolean testSmaller26(int a, int b) { + return compare9(a, b) < 0; + } + + @Test(op = Operation.SMALLER) + public static boolean testSmaller27(int a, int b) { + return compare9(a, b) <= -1; + } + + @Test(op = Operation.SMALLER) + public static boolean testSmaller28(int a, int b) { + return compare10(a, b) == -1; + } + + @Test(op = Operation.SMALLER) + public static boolean testSmaller29(int a, int b) { + return compare10(a, b) < 0; + } + + @Test(op = Operation.SMALLER) + public static boolean testSmaller30(int a, int b) { + return compare10(a, b) <= -1; + } + + + @Test(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual1(int a, int b) { + return compare1(a, b) <= 0; + } + + @Test(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual2(int a, int b) { + return compare2(a, b) <= 0; + } + + @Test(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual3(int a, int b) { + return compare3(a, b) <= 0; + } + + @Test(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual4(int a, int b) { + return compare4(a, b) <= 0; + } + + @Test(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual5(int a, int b) { + return compare5(a, b) <= 0; + } + + @Test(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual6(int a, int b) { + return compare6(a, b) <= 0; + } + + @Test(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual7(int a, int b) { + return compare7(a, b) <= 0; + } + + @Test(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual8(int a, int b) { + return compare8(a, b) <= 0; + } + + @Test(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual9(int a, int b) { + return compare9(a, b) <= 0; + } + + @Test(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual10(int a, int b) { + return compare10(a, b) <= 0; + } + + + @Test(op = Operation.EQUAL) + public static boolean testEqual1(int a, int b) { + return compare1(a, b) == 0; + } + + @Test(op = Operation.EQUAL) + public static boolean testEqual2(int a, int b) { + return compare2(a, b) == 0; + } + + @Test(op = Operation.EQUAL) + public static boolean testEqual3(int a, int b) { + return compare3(a, b) == 0; + } + + @Test(op = Operation.EQUAL) + public static boolean testEqual4(int a, int b) { + return compare4(a, b) == 0; + } + + @Test(op = Operation.EQUAL) + public static boolean testEqual5(int a, int b) { + return compare5(a, b) == 0; + } + + @Test(op = Operation.EQUAL) + public static boolean testEqual6(int a, int b) { + return compare6(a, b) == 0; + } + + @Test(op = Operation.EQUAL) + public static boolean testEqual7(int a, int b) { + return compare7(a, b) == 0; + } + + @Test(op = Operation.EQUAL) + public static boolean testEqual8(int a, int b) { + return compare8(a, b) == 0; + } + + @Test(op = Operation.EQUAL) + public static boolean testEqual9(int a, int b) { + return compare9(a, b) == 0; + } + + @Test(op = Operation.EQUAL) + public static boolean testEqual10(int a, int b) { + return compare10(a, b) == 0; + } + + + @Test(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual1(int a, int b) { + return compare1(a, b) >= 0; + } + + @Test(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual2(int a, int b) { + return compare2(a, b) >= 0; + } + + @Test(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual3(int a, int b) { + return compare3(a, b) >= 0; + } + + @Test(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual4(int a, int b) { + return compare4(a, b) >= 0; + } + + @Test(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual5(int a, int b) { + return compare5(a, b) >= 0; + } + + @Test(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual6(int a, int b) { + return compare6(a, b) >= 0; + } + + @Test(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual7(int a, int b) { + return compare7(a, b) >= 0; + } + + @Test(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual8(int a, int b) { + return compare8(a, b) >= 0; + } + + @Test(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual9(int a, int b) { + return compare9(a, b) >= 0; + } + + @Test(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual10(int a, int b) { + return compare10(a, b) >= 0; + } + + + @Test(op = Operation.GREATER) + public static boolean testGreater1(int a, int b) { + return compare1(a, b) == 1; + } + + @Test(op = Operation.GREATER) + public static boolean testGreater2(int a, int b) { + return compare1(a, b) > 0; + } + + @Test(op = Operation.GREATER) + public static boolean testGreater3(int a, int b) { + return compare1(a, b) >= 1; + } + + @Test(op = Operation.GREATER) + public static boolean testGreater4(int a, int b) { + return compare2(a, b) == 1; + } + + @Test(op = Operation.GREATER) + public static boolean testGreater5(int a, int b) { + return compare2(a, b) > 0; + } + + @Test(op = Operation.GREATER) + public static boolean testGreater6(int a, int b) { + return compare2(a, b) >= 1; + } + + @Test(op = Operation.GREATER) + public static boolean testGreater7(int a, int b) { + return compare3(a, b) == 1; + } + + @Test(op = Operation.GREATER) + public static boolean testGreater8(int a, int b) { + return compare3(a, b) > 0; + } + + @Test(op = Operation.GREATER) + public static boolean testGreater9(int a, int b) { + return compare3(a, b) >= 1; + } + + @Test(op = Operation.GREATER) + public static boolean testGreater10(int a, int b) { + return compare4(a, b) == 1; + } + + @Test(op = Operation.GREATER) + public static boolean testGreater11(int a, int b) { + return compare4(a, b) > 0; + } + + @Test(op = Operation.GREATER) + public static boolean testGreater12(int a, int b) { + return compare4(a, b) >= 1; + } + + @Test(op = Operation.GREATER) + public static boolean testGreater13(int a, int b) { + return compare5(a, b) == 1; + } + + @Test(op = Operation.GREATER) + public static boolean testGreater14(int a, int b) { + return compare5(a, b) > 0; + } + + @Test(op = Operation.GREATER) + public static boolean testGreater15(int a, int b) { + return compare5(a, b) >= 1; + } + + @Test(op = Operation.GREATER) + public static boolean testGreater16(int a, int b) { + return compare6(a, b) == 1; + } + + @Test(op = Operation.GREATER) + public static boolean testGreater17(int a, int b) { + return compare6(a, b) > 0; + } + + @Test(op = Operation.GREATER) + public static boolean testGreater18(int a, int b) { + return compare6(a, b) >= 1; + } + + @Test(op = Operation.GREATER) + public static boolean testGreater19(int a, int b) { + return compare7(a, b) == 1; + } + + @Test(op = Operation.GREATER) + public static boolean testGreater20(int a, int b) { + return compare7(a, b) > 0; + } + + @Test(op = Operation.GREATER) + public static boolean testGreater21(int a, int b) { + return compare7(a, b) >= 1; + } + + @Test(op = Operation.GREATER) + public static boolean testGreater22(int a, int b) { + return compare8(a, b) == 1; + } + + @Test(op = Operation.GREATER) + public static boolean testGreater23(int a, int b) { + return compare8(a, b) > 0; + } + + @Test(op = Operation.GREATER) + public static boolean testGreater24(int a, int b) { + return compare8(a, b) >= 1; + } + + @Test(op = Operation.GREATER) + public static boolean testGreater25(int a, int b) { + return compare9(a, b) == 1; + } + + @Test(op = Operation.GREATER) + public static boolean testGreater26(int a, int b) { + return compare9(a, b) > 0; + } + + @Test(op = Operation.GREATER) + public static boolean testGreater27(int a, int b) { + return compare9(a, b) >= 1; + } + + @Test(op = Operation.GREATER) + public static boolean testGreater28(int a, int b) { + return compare10(a, b) == 1; + } + + @Test(op = Operation.GREATER) + public static boolean testGreater29(int a, int b) { + return compare10(a, b) > 0; + } + + @Test(op = Operation.GREATER) + public static boolean testGreater30(int a, int b) { + return compare10(a, b) >= 1; + } + + + @Test(op = Operation.ALWAYS_FALSE) + public static boolean testAlwaysFalse1(int a, int b) { + return compare11(a, b) == 2; + } + + @Test(op = Operation.ALWAYS_FALSE) + public static boolean testAlwaysFalse2(int a, int b) { + return compare11(a, b) > 1; + } + + @Test(op = Operation.ALWAYS_FALSE) + public static boolean testAlwaysFalse3(int a, int b) { + return compare11(a, b) >= 2; + } + + @Test(op = Operation.ALWAYS_FALSE) + public static boolean testAlwaysFalse4(int a, int b) { + return compare12(a, b) == 2; + } + + @Test(op = Operation.ALWAYS_FALSE) + public static boolean testAlwaysFalse5(int a, int b) { + return compare12(a, b) > 1; + } + + @Test(op = Operation.ALWAYS_FALSE) + public static boolean testAlwaysFalse6(int a, int b) { + return compare12(a, b) >= 2; + } + + @Test(op = Operation.ALWAYS_FALSE) + public static boolean testAlwaysFalse7(int a, int b) { + return compare13(a, b) == 2; + } + + @Test(op = Operation.ALWAYS_FALSE) + public static boolean testAlwaysFalse8(int a, int b) { + return compare13(a, b) > 1; + } + + @Test(op = Operation.ALWAYS_FALSE) + public static boolean testAlwaysFalse9(int a, int b) { + return compare13(a, b) >= 2; + } + + @Test(op = Operation.ALWAYS_FALSE) + public static boolean testAlwaysFalse10(int a, int b) { + return compare14(a, b) == 2; + } + + @Test(op = Operation.ALWAYS_FALSE) + public static boolean testAlwaysFalse11(int a, int b) { + return compare14(a, b) > 1; + } + + @Test(op = Operation.ALWAYS_FALSE) + public static boolean testAlwaysFalse12(int a, int b) { + return compare14(a, b) >= 2; + } + + public static void main(String[] args) throws Exception { + for (int i = 0; i < 20_000; ++i) { + for (Method m : TestTrichotomyExpressions.class.getMethods()) { + if (m.isAnnotationPresent(Test.class)) { + Operation op = m.getAnnotation(Test.class).op(); + boolean result = (boolean)m.invoke(null, 0, 0); + Asserts.assertEquals(result, (op == Operation.EQUAL || op == Operation.SMALLER_EQUAL || op == Operation.GREATER_EQUAL) ? true : false); + result = (boolean)m.invoke(null, 0, 1); + Asserts.assertEquals(result, (op == Operation.SMALLER || op == Operation.SMALLER_EQUAL) ? true : false); + result = (boolean)m.invoke(null, 1, 0); + Asserts.assertEquals(result, (op == Operation.GREATER || op == Operation.GREATER_EQUAL) ? true : false); + } + } + } + } +}