8323220: Reassociate loop invariants involved in Cmps and Add/Subs

Reviewed-by: epeter, xliu, chagedorn
This commit is contained in:
Joshua Cao 2024-04-15 15:54:34 +00:00 committed by Emanuel Peter
parent a293bdff91
commit 140f56718b
4 changed files with 994 additions and 21 deletions

View File

@ -254,11 +254,10 @@ void IdealLoopTree::compute_profile_trip_cnt(PhaseIdealLoop *phase) {
head->set_profile_trip_cnt(trip_cnt);
}
//---------------------find_invariant-----------------------------
// Return nonzero index of invariant operand for an associative
// binary operation of (nonconstant) invariant and variant values.
// Helper for reassociate_invariants.
int IdealLoopTree::find_invariant(Node* n, PhaseIdealLoop *phase) {
int IdealLoopTree::find_invariant(Node* n, PhaseIdealLoop* phase) {
bool in1_invar = this->is_invariant(n->in(1));
bool in2_invar = this->is_invariant(n->in(2));
if (in1_invar && !in2_invar) return 1;
@ -266,7 +265,24 @@ int IdealLoopTree::find_invariant(Node* n, PhaseIdealLoop *phase) {
return 0;
}
//---------------------is_associative-----------------------------
// Return TRUE if "n" is an associative cmp node. A cmp node is
// associative if it is only used for equals or not-equals
// comparisons of integers or longs. We cannot reassociate
// non-equality comparisons due to possibility of overflow.
bool IdealLoopTree::is_associative_cmp(Node* n) {
if (n->Opcode() != Op_CmpI && n->Opcode() != Op_CmpL) {
return false;
}
for (DUIterator i = n->outs(); n->has_out(i); i++) {
BoolNode* bool_out = n->out(i)->isa_Bool();
if (bool_out == nullptr || !(bool_out->_test._test == BoolTest::eq ||
bool_out->_test._test == BoolTest::ne)) {
return false;
}
}
return true;
}
// Return TRUE if "n" is an associative binary node. If "base" is
// not null, "n" must be re-associative with it.
bool IdealLoopTree::is_associative(Node* n, Node* base) {
@ -274,25 +290,26 @@ bool IdealLoopTree::is_associative(Node* n, Node* base) {
if (base != nullptr) {
assert(is_associative(base), "Base node should be associative");
int base_op = base->Opcode();
if (base_op == Op_AddI || base_op == Op_SubI) {
if (base_op == Op_AddI || base_op == Op_SubI || base_op == Op_CmpI) {
return op == Op_AddI || op == Op_SubI;
}
if (base_op == Op_AddL || base_op == Op_SubL) {
if (base_op == Op_AddL || base_op == Op_SubL || base_op == Op_CmpL) {
return op == Op_AddL || op == Op_SubL;
}
return op == base_op;
} else {
// Integer "add/sub/mul/and/or/xor" operations are associative.
// Integer "add/sub/mul/and/or/xor" operations are associative. Integer
// "cmp" operations are associative if it is an equality comparison.
return op == Op_AddI || op == Op_AddL
|| op == Op_SubI || op == Op_SubL
|| op == Op_MulI || op == Op_MulL
|| op == Op_AndI || op == Op_AndL
|| op == Op_OrI || op == Op_OrL
|| op == Op_XorI || op == Op_XorL;
|| op == Op_XorI || op == Op_XorL
|| is_associative_cmp(n);
}
}
//---------------------reassociate_add_sub------------------------
// Reassociate invariant add and subtract expressions:
//
// inv1 + (x + inv2) => ( inv1 + inv2) + x
@ -308,22 +325,32 @@ bool IdealLoopTree::is_associative(Node* n, Node* base) {
// (inv2 - x) - inv1 => (-inv1 + inv2) - x
// inv1 - (x + inv2) => ( inv1 - inv2) - x
//
Node* IdealLoopTree::reassociate_add_sub(Node* n1, int inv1_idx, int inv2_idx, PhaseIdealLoop *phase) {
assert(n1->is_Add() || n1->is_Sub(), "Target node should be add or subtract");
// Apply the same transformations to == and !=
// inv1 == (x + inv2) => ( inv1 - inv2 ) == x
// inv1 == (x - inv2) => ( inv1 + inv2 ) == x
// inv1 == (inv2 - x) => (-inv1 + inv2 ) == x
Node* IdealLoopTree::reassociate_add_sub_cmp(Node* n1, int inv1_idx, int inv2_idx, PhaseIdealLoop* phase) {
Node* n2 = n1->in(3 - inv1_idx);
bool n1_is_sub = n1->is_Sub() && !n1->is_Cmp();
bool n1_is_cmp = n1->is_Cmp();
bool n2_is_sub = n2->is_Sub();
assert(n1->is_Add() || n1_is_sub || n1_is_cmp, "Target node should be add, subtract, or compare");
assert(n2->is_Add() || (n2_is_sub && !n2->is_Cmp()), "Child node should be add or subtract");
Node* inv1 = n1->in(inv1_idx);
Node* inv2 = n2->in(inv2_idx);
Node* x = n2->in(3 - inv2_idx);
bool neg_x = n2->is_Sub() && inv2_idx == 1;
bool neg_inv2 = n2->is_Sub() && inv2_idx == 2;
bool neg_inv1 = n1->is_Sub() && inv1_idx == 2;
if (n1->is_Sub() && inv1_idx == 1) {
// Determine whether x, inv1, or inv2 should be negative in the transformed
// expression
bool neg_x = n2_is_sub && inv2_idx == 1;
bool neg_inv2 = (n2_is_sub && !n1_is_cmp && inv2_idx == 2) || (n1_is_cmp && !n2_is_sub);
bool neg_inv1 = (n1_is_sub && inv1_idx == 2) || (n1_is_cmp && inv2_idx == 1 && n2_is_sub);
if (n1_is_sub && inv1_idx == 1) {
neg_x = !neg_x;
neg_inv2 = !neg_inv2;
}
bool is_int = n1->bottom_type()->isa_int() != nullptr;
bool is_int = n2->bottom_type()->isa_int() != nullptr;
Node* inv1_c = phase->get_ctrl(inv1);
Node* n_inv1;
if (neg_inv1) {
@ -349,6 +376,9 @@ Node* IdealLoopTree::reassociate_add_sub(Node* n1, int inv1_idx, int inv2_idx, P
inv = new AddINode(n_inv1, inv2);
}
phase->register_new_node(inv, phase->get_early_ctrl(inv));
if (n1_is_cmp) {
return new CmpINode(x, inv);
}
if (neg_x) {
return new SubINode(inv, x);
} else {
@ -361,6 +391,9 @@ Node* IdealLoopTree::reassociate_add_sub(Node* n1, int inv1_idx, int inv2_idx, P
inv = new AddLNode(n_inv1, inv2);
}
phase->register_new_node(inv, phase->get_early_ctrl(inv));
if (n1_is_cmp) {
return new CmpLNode(x, inv);
}
if (neg_x) {
return new SubLNode(inv, x);
} else {
@ -369,10 +402,9 @@ Node* IdealLoopTree::reassociate_add_sub(Node* n1, int inv1_idx, int inv2_idx, P
}
}
//---------------------reassociate-----------------------------
// Reassociate invariant binary expressions with add/sub/mul/
// and/or/xor operators.
// For add/sub expressions: see "reassociate_add_sub"
// and/or/xor/cmp operators.
// For add/sub/cmp expressions: see "reassociate_add_sub_cmp"
//
// For mul/and/or/xor expressions:
//
@ -399,7 +431,9 @@ Node* IdealLoopTree::reassociate(Node* n1, PhaseIdealLoop *phase) {
case Op_AddL:
case Op_SubI:
case Op_SubL:
result = reassociate_add_sub(n1, inv1_idx, inv2_idx, phase);
case Op_CmpI:
case Op_CmpL:
result = reassociate_add_sub_cmp(n1, inv1_idx, inv2_idx, phase);
break;
case Op_MulI:
case Op_MulL:

View File

@ -739,13 +739,15 @@ public:
void reassociate_invariants(PhaseIdealLoop *phase);
// Reassociate invariant binary expressions.
Node* reassociate(Node* n1, PhaseIdealLoop *phase);
// Reassociate invariant add and subtract expressions.
Node* reassociate_add_sub(Node* n1, int inv1_idx, int inv2_idx, PhaseIdealLoop *phase);
// Reassociate invariant add, subtract, and compare expressions.
Node* reassociate_add_sub_cmp(Node* n1, int inv1_idx, int inv2_idx, PhaseIdealLoop* phase);
// Return nonzero index of invariant operand if invariant and variant
// are combined with an associative binary. Helper for reassociate_invariants.
int find_invariant(Node* n, PhaseIdealLoop *phase);
// Return TRUE if "n" is associative.
bool is_associative(Node* n, Node* base=nullptr);
// Return TRUE if "n" is an associative cmp node.
bool is_associative_cmp(Node* n);
// Return true if n is invariant
bool is_invariant(Node* n) const;

View File

@ -0,0 +1,525 @@
/*
* Copyright Amazon.com Inc. 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.
*/
package compiler.c2.loopopts;
import compiler.lib.ir_framework.*;
import jdk.test.lib.Asserts;
import jdk.test.lib.Utils;
import java.util.Random;
/*
* @test
* @bug 8323220
* @summary Test loop invariant code motion of add/sub through reassociation
* @library /test/lib /
* @run driver compiler.c2.loopopts.InvariantCodeMotionReassociateAddSub
*/
public class InvariantCodeMotionReassociateAddSub {
private static final Random RANDOM = Utils.getRandomInstance();
private int size;
private int inv1;
private int inv2;
public static void main(String[] args) {
TestFramework.run();
}
@DontInline
private int blackhole(int i) { return i; }
@DontInline
private int blackhole(long i) { return (int)i; }
@Setup
public Object[] setup(SetupInfo info) {
int count = info.invocationCounter();
size = count + 500;
inv1 = count;
if (RANDOM.nextInt() % 7 == 0) {
// Setup inputs to be equals sometimes to avoid uncommon traps
inv2 = inv1;
} else {
inv2 = count * 2;
}
return new Object[] { inv1, inv2, size };
}
public void fail(int returnValue) {
throw new RuntimeException("Illegal reassociation: returnValue=" + returnValue + ", inv1=" + inv1
+ ", inv2=" + inv2 + ", size=" + size);
}
public void check(int returnValue, int expected) {
if (returnValue != expected) {
fail(returnValue);
}
}
public void checkAdd(int returnValue) {
check(returnValue, inv1 + inv2 + size - 1);
}
public void checkSubAdd(int returnValue) {
check(returnValue, inv1 - inv2 + size - 1);
}
public void checkNegSubAdd(int returnValue) {
check(returnValue, -inv1 - inv2 + size - 1);
}
public void checkAddSub(int returnValue) {
check(returnValue, inv1 + inv2 - (size - 1));
}
public void checkSubSub(int returnValue) {
check(returnValue, inv1 - inv2 - (size - 1));
}
@Test
@Arguments(setup = "setup")
@IR(counts = {IRNode.ADD_I, "3"})
public int addInt(int inv1, int inv2, int size) {
int result = -1;
for (int i = 0; i < size; ++i) {
// Reassociate to `inv1 + inv2 + i`
result = blackhole(inv1 + i + inv2);
}
return result;
}
@Check(test = "addInt")
public void checkAddInt(int returnValue) {
checkAdd(returnValue);
}
@Test
@Arguments(setup = "setup")
@IR(counts = {IRNode.ADD_L, "2"})
public int addLong(long inv1, long inv2, int size) {
int result = -1;
for (int i = 0; i < size; ++i) {
// Reassociate to `inv1 + inv2 + i`
result = blackhole(inv1 + i + inv2);
}
return result;
}
@Check(test = "addLong")
public void checkAddLong(int returnValue) {
checkAdd(returnValue);
}
@Test
@Arguments(setup = "setup")
@IR(counts = {IRNode.ADD_I, "3"})
public int addInt2(int inv1, int inv2, int size) {
int result = -1;
for (int i = 0; i < size; ++i) {
// Reassociate to `inv1 + inv2 + i`
result = blackhole(inv1 + (i + inv2));
}
return result;
}
@Check(test = "addInt2")
public void checkAddInt2(int returnValue) {
checkAdd(returnValue);
}
@Test
@Arguments(setup = "setup")
@IR(counts = {IRNode.ADD_L, "2"})
public int addLong2(long inv1, long inv2, int size) {
int result = -1;
for (int i = 0; i < size; ++i) {
// Reassociate to `inv1 + inv2 + i`
result = blackhole(inv1 + (i + inv2));
}
return result;
}
@Check(test = "addLong2")
public void checkAddLong2(int returnValue) {
checkAdd(returnValue);
}
@Test
@Arguments(setup = "setup")
@IR(counts = {IRNode.ADD_I, "2"})
@IR(counts = {IRNode.SUB_I, "1"})
public int minusAddInt(int inv1, int inv2, int size) {
int result = -1;
for (int i = 0; i < size; ++i) {
// Reassociate to `inv1 - inv2 + i`
result = blackhole(inv1 + (i - inv2));
}
return result;
}
@Check(test = "minusAddInt")
public void checkSubAddInt(int returnValue) {
checkSubAdd(returnValue);
}
@Test
@Arguments(setup = "setup")
@IR(counts = {IRNode.ADD_L, "1"})
@IR(counts = {IRNode.SUB_L, "1"})
public int minusAddLong(long inv1, long inv2, int size) {
int result = -1;
for (int i = 0; i < size; ++i) {
// Reassociate to `inv1 - inv2 + i`
result = blackhole(inv1 + (i - inv2));
}
return result;
}
@Check(test = "minusAddLong")
public void checkSubAddLong(int returnValue) {
checkSubAdd(returnValue);
}
@Test
@Arguments(setup = "setup")
@IR(counts = {IRNode.ADD_I, "2"})
@IR(counts = {IRNode.SUB_I, "1"})
public int minusAddInt2(int inv1, int inv2, int size) {
int result = -1;
for (int i = 0; i < size; ++i) {
// Reassociate to `inv1 - inv2 + i`
result = blackhole(inv1 - (inv2 - i));
}
return result;
}
@Check(test = "minusAddInt2")
public void checkSubAddInt2(int returnValue) {
checkSubAdd(returnValue);
}
@Test
@Arguments(setup = "setup")
@IR(counts = {IRNode.ADD_L, "1"})
@IR(counts = {IRNode.SUB_L, "1"})
public int minusAddLong2(long inv1, long inv2, int size) {
int result = -1;
for (int i = 0; i < size; ++i) {
// Reassociate to `inv1 - inv2 + i`
result = blackhole(inv1 - (inv2 - i));
}
return result;
}
@Check(test = "minusAddLong2")
public void checkSubAddLong2(int returnValue) {
checkSubAdd(returnValue);
}
@Test
@Arguments(setup = "setup")
@IR(counts = {IRNode.ADD_I, "2"})
@IR(counts = {IRNode.SUB_I, "1"})
public int minusAddInt3(int inv1, int inv2, int size) {
int result = -1;
for (int i = 0; i < size; ++i) {
// Reassociate to `inv1 - inv2 + i`
result = blackhole(i - inv2 + inv1);
}
return result;
}
@Check(test = "minusAddInt3")
public void checkSubAddInt3(int returnValue) {
checkSubAdd(returnValue);
}
@Test
@Arguments(setup = "setup")
@IR(counts = {IRNode.ADD_L, "1"})
@IR(counts = {IRNode.SUB_L, "1"})
public int minusAddLong3(long inv1, long inv2, int size) {
int result = -1;
for (int i = 0; i < size; ++i) {
// Reassociate to `inv1 - inv2 + i`
result = blackhole(i - inv2 + inv1);
}
return result;
}
@Check(test = "minusAddLong3")
public void checkSubAddLong3(int returnValue) {
checkSubAdd(returnValue);
}
@Test
@Arguments(setup = "setup")
@IR(counts = {IRNode.ADD_I, "2"})
@IR(counts = {IRNode.SUB_I, "1"})
public int negAddInt(int inv1, int inv2, int size) {
int result = -1;
for (int i = 0; i < size; ++i) {
// Reassociate to `-inv2 + inv1 + i`
result = blackhole(i + inv1 - inv2);
}
return result;
}
@Check(test = "negAddInt")
public void checkNegAddInt(int returnValue) {
checkSubAdd(returnValue);
}
@Test
@Arguments(setup = "setup")
@IR(counts = {IRNode.ADD_L, "1"})
@IR(counts = {IRNode.SUB_L, "1"})
public int negAddLong(long inv1, long inv2, int size) {
int result = -1;
for (int i = 0; i < size; ++i) {
// Reassociate to `-inv2 + inv1 + i`
result = blackhole(i + inv1 - inv2);
}
return result;
}
@Check(test = "negAddLong")
public void checkNegAddLong(int returnValue) {
checkSubAdd(returnValue);
}
@Test
@Arguments(setup = "setup")
@IR(counts = {IRNode.ADD_I, "2"})
@IR(counts = {IRNode.SUB_I, "2"})
public int negSubAddInt(int inv1, int inv2, int size) {
int result = -1;
for (int i = 0; i < size; ++i) {
// Reassociate to `-inv1 - inv2 + i`
result = blackhole(i - inv1 - inv2);
}
return result;
}
@Check(test = "negSubAddInt")
public void checkNegSubAddInt(int returnValue) {
checkNegSubAdd(returnValue);
}
@Test
@Arguments(setup = "setup")
@IR(counts = {IRNode.ADD_L, "1"})
@IR(counts = {IRNode.SUB_L, "2"})
public int negSubAddLong(long inv1, long inv2, int size) {
int result = -1;
for (int i = 0; i < size; ++i) {
// Reassociate to `-inv1 - inv2 + i`
result = blackhole(i - inv1 - inv2);
}
return result;
}
@Check(test = "negSubAddLong")
public void checkNegSubAddLong(int returnValue) {
checkNegSubAdd(returnValue);
}
@Test
@Arguments(setup = "setup")
@IR(counts = {IRNode.ADD_I, "3"})
@IR(counts = {IRNode.SUB_I, "1"})
public int addSubInt(int inv1, int inv2, int size) {
int result = -1;
for (int i = 0; i < size; ++i) {
// Reassociate to `inv1 + inv2 - i`
result = blackhole(inv1 + (inv2 - i));
}
return result;
}
@Check(test = "addSubInt")
public void checkAddSubInt(int returnValue) {
checkAddSub(returnValue);
}
@Test
@Arguments(setup = "setup")
@IR(counts = {IRNode.ADD_L, "1"})
@IR(counts = {IRNode.SUB_L, "1"})
public int addSubLong(long inv1, long inv2, int size) {
int result = -1;
for (int i = 0; i < size; ++i) {
// Reassociate to `inv1 + inv2 - i`
result = blackhole(inv1 + (inv2 - i));
}
return result;
}
@Check(test = "addSubLong")
public void checkAddSubLong(int returnValue) {
checkAddSub(returnValue);
}
@Test
@Arguments(setup = "setup")
@IR(counts = {IRNode.ADD_I, "3"})
@IR(counts = {IRNode.SUB_I, "1"})
public int addSubInt2(int inv1, int inv2, int size) {
int result = -1;
for (int i = 0; i < size; ++i) {
// Reassociate to `inv1 + inv2 - i`
result = blackhole(inv1 - (i - inv2));
}
return result;
}
@Check(test = "addSubInt2")
public void checkAddSubInt2(int returnValue) {
checkAddSub(returnValue);
}
@Test
@Arguments(setup = "setup")
@IR(counts = {IRNode.ADD_L, "1"})
@IR(counts = {IRNode.SUB_L, "1"})
public int addSubLong2(long inv1, long inv2, int size) {
int result = -1;
for (int i = 0; i < size; ++i) {
// Reassociate to `inv1 + inv2 - i`
result = blackhole(inv1 - (i - inv2));
}
return result;
}
@Check(test = "addSubLong2")
public void checkAddSubLong2(int returnValue) {
checkAddSub(returnValue);
}
@Test
@Arguments(setup = "setup")
@IR(counts = {IRNode.ADD_I, "3"})
@IR(counts = {IRNode.SUB_I, "1"})
public int addSubInt3(int inv1, int inv2, int size) {
int result = -1;
for (int i = 0; i < size; ++i) {
// Reassociate to `inv1 + inv2 - i`
result = blackhole(inv2 - i + inv1);
}
return result;
}
@Check(test = "addSubInt3")
public void checkAddSubInt3(int returnValue) {
checkAddSub(returnValue);
}
@Test
@Arguments(setup = "setup")
@IR(counts = {IRNode.ADD_L, "1"})
@IR(counts = {IRNode.SUB_L, "1"})
public int addSubLong3(long inv1, long inv2, int size) {
int result = -1;
for (int i = 0; i < size; ++i) {
// Reassociate to `inv1 + inv2 - i`
result = blackhole(inv2 - i + inv1);
}
return result;
}
@Check(test = "addSubLong3")
public void checkAddSubLong3(int returnValue) {
checkAddSub(returnValue);
}
@Test
@Arguments(setup = "setup")
@IR(counts = {IRNode.ADD_I, "2"})
@IR(counts = {IRNode.SUB_I, "2"})
public int subSubInt(int inv1, int inv2, int size) {
int result = -1;
for (int i = 0; i < size; ++i) {
// Reassociate to `inv1 - inv2 - i`
result = blackhole(inv1 - (i + inv2));
}
return result;
}
@Check(test = "subSubInt")
public void checkSubSubInt(int returnValue) {
checkSubSub(returnValue);
}
@Test
@Arguments(setup = "setup")
@IR(failOn = {IRNode.ADD_L})
@IR(counts = {IRNode.SUB_L, "2"})
public int subSubLong(long inv1, long inv2, int size) {
int result = -1;
for (int i = 0; i < size; ++i) {
// Reassociate to `inv1 - inv2 - i`
result = blackhole(inv1 - (i + inv2));
}
return result;
}
@Check(test = "subSubLong")
public void checkSubSubLong(int returnValue) {
checkSubSub(returnValue);
}
@Test
@Arguments(setup = "setup")
@IR(counts = {IRNode.ADD_I, "2"})
@IR(counts = {IRNode.SUB_I, "2"})
public int subSubInt2(int inv1, int inv2, int size) {
int result = -1;
for (int i = 0; i < size; ++i) {
// Reassociate to `inv1 - inv2 - i`
result = blackhole(inv1 - i - inv2);
}
return result;
}
@Check(test = "subSubInt2")
public void checkSubSubInt2(int returnValue) {
checkSubSub(returnValue);
}
@Test
@Arguments(setup = "setup")
@IR(failOn = {IRNode.ADD_L})
@IR(counts = {IRNode.SUB_L, "2"})
public int subSubLong2(long inv1, long inv2, int size) {
int result = -1;
for (int i = 0; i < size; ++i) {
// Reassociate to `inv1 - inv2 - i`
result = blackhole(inv1 - i - inv2);
}
return result;
}
@Check(test = "subSubLong2")
public void checkSubSubLong2(int returnValue) {
checkSubSub(returnValue);
}
}

View File

@ -0,0 +1,412 @@
/*
* Copyright Amazon.com Inc. 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.
*/
package compiler.c2.loopopts;
import compiler.lib.ir_framework.*;
import jdk.test.lib.Asserts;
import jdk.test.lib.Utils;
import java.util.Random;
/*
* @test
* @bug 8323220
* @summary Test loop invariant code motion for cmp nodes through reassociation
* @library /test/lib /
* @run driver compiler.c2.loopopts.InvariantCodeMotionReassociateCmp
*/
public class InvariantCodeMotionReassociateCmp {
private static final Random RANDOM = Utils.getRandomInstance();
private int size;
private int inv1;
private int inv2;
public static void main(String[] args) {
TestFramework.run();
}
@DontInline
private void blackhole() {}
@Setup
public Object[] setup(SetupInfo info) {
int count = info.invocationCounter();
size = count + 500;
inv1 = count;
if (RANDOM.nextInt() % 7 == 0) {
// Setup inputs to be equals sometimes to avoid uncommon traps
inv2 = inv1;
} else {
inv2 = count * 2;
}
return new Object[] { inv1, inv2, size };
}
public void fail(int returnValue) {
throw new RuntimeException("Illegal reassociation: returnValue=" + returnValue + ", inv1=" + inv1
+ ", inv2=" + inv2 + ", size=" + size);
}
public void checkEq(int returnValue) {
int invDiff = inv2 - inv1;
if ((invDiff < size && returnValue != invDiff) || (invDiff >= size && returnValue != size)) {
fail(returnValue);
}
}
public void checkNe(int returnValue) {
int invDiff = inv2 - inv1;
if ((invDiff != 0 && returnValue != 0) || (invDiff == 0 && returnValue != 1)) {
fail(returnValue);
}
}
@Test
@Arguments(setup = "setup")
@IR(counts = {IRNode.SUB_I, "1"})
public int equalsAddInt(int inv1, int inv2, int size) {
int i = 0;
for (; i < size; ++i) {
blackhole();
// Reassociate to `inv2 - inv1 == i`
if (inv1 + i == inv2) {
break;
}
}
return i;
}
@Check(test = "equalsAddInt")
public void checkEqualsAddInt(int returnValue) {
checkEq(returnValue);
}
@Test
@Arguments(setup = "setup")
@IR(counts = {IRNode.SUB_L, "1"})
public int equalsAddLong(long inv1, long inv2, int size) {
int i = 0;
for (; i < size; ++i) {
blackhole();
// Reassociate to `inv2 - inv1 == i`
if (inv1 + i == inv2) {
break;
}
}
return i;
}
@Check(test = "equalsAddLong")
public void checkEqualsAddLong(int returnValue) {
checkEq(returnValue);
}
@Test
@Arguments(setup = "setup")
@IR(counts = {IRNode.SUB_I, "1"})
public int equalsInvariantSubVariantInt(int inv1, int inv2, int size) {
int i = 0;
for (; i < size; ++i) {
blackhole();
// Reassociate to `inv1 - inv2 == i`
if (inv2 - i == inv1) {
break;
}
}
return i;
}
@Check(test = "equalsInvariantSubVariantInt")
public void checkEqualsInvariantSubVariantInt(int returnValue) {
checkEq(returnValue);
}
@Test
@Arguments(setup = "setup")
@IR(counts = {IRNode.SUB_L, "1"})
public int equalsInvariantSubVariantLong(long inv1, long inv2, int size) {
int i = 0;
for (; i < size; ++i) {
blackhole();
// Reassociate to `inv2 - inv1 == i`
if (inv2 - i == inv1) {
break;
}
}
return i;
}
@Check(test = "equalsInvariantSubVariantLong")
public void checkEqualsInvariantSubVariantLong(int returnValue) {
checkEq(returnValue);
}
@Test
@Arguments(setup = "setup")
@IR(counts = {IRNode.SUB_I, "1"})
public int equalsVariantSubInvariantInt(int inv1, int inv2, int size) {
int i = 0;
for (; i < size; ++i) {
blackhole();
// Reassociate to `inv2 - inv1 == i`
if (i - inv2 == -inv1) {
break;
}
}
return i;
}
@Check(test = "equalsVariantSubInvariantInt")
public void checkEqualsVariantSubInvariantInt(int returnValue) {
checkEq(returnValue);
}
@Test
@Arguments(setup = "setup")
@IR(counts = {IRNode.SUB_L, "1"})
public int equalsVariantSubInvariantLong(long inv1, long inv2, int size) {
int i = 0;
for (; i < size; ++i) {
blackhole();
// Reassociate to `inv2 - inv1 == i`
if (i - inv2 == -inv1) {
break;
}
}
return i;
}
@Check(test = "equalsVariantSubInvariantLong")
public void checkEqualsVariantSubInvariantLong(int returnValue) {
checkEq(returnValue);
}
@Test
@Arguments(setup = "setup")
@IR(counts = {IRNode.SUB_I, "1"})
public int notEqualsAddInt(int inv1, int inv2, int size) {
int i = 0;
for (; i < 500; ++i) {
blackhole();
// Reassociate to `inv1 - inv2 != i`
if (inv1 + i != inv2) {
break;
}
}
return i;
}
@Check(test = "notEqualsAddInt")
public void checkNotEqualsAddInt(int returnValue) {
checkNe(returnValue);
}
@Test
@Arguments(setup = "setup")
@IR(counts = {IRNode.SUB_L, "1"})
public int notEqualsAddLong(long inv1, long inv2, int size) {
int i = 0;
for (; i < size; ++i) {
blackhole();
// Reassociate to `inv1 - inv2 != i`
if (inv1 + i != inv2) {
break;
}
}
return i;
}
@Check(test = "notEqualsAddLong")
public void checkNotEqualsAddLong(int returnValue) {
checkNe(returnValue);
}
@Test
@Arguments(setup = "setup")
@IR(counts = {IRNode.SUB_I, "1"})
public int notEqualsInvariantSubVariantInt(int inv1, int inv2, int size) {
int i = 0;
for (; i < size; ++i) {
blackhole();
// Reassociate to `inv1 - inv2 != i`
if (inv1 - i != inv2) {
break;
}
}
return i;
}
@Check(test = "notEqualsInvariantSubVariantInt")
public void checkNotEqualsInvariantSubVariantInt(int returnValue) {
checkNe(returnValue);
}
@Test
@Arguments(setup = "setup")
@IR(counts = {IRNode.SUB_L, "1"})
public int notEqualsInvariantSubVariantLong(long inv1, long inv2, int size) {
int i = 0;
for (; i < size; ++i) {
blackhole();
// Reassociate to `inv1 - inv2 != i`
if (inv1 - i != inv2) {
break;
}
}
return i;
}
@Check(test = "notEqualsInvariantSubVariantLong")
public void checkNotEqualsInvariantSubVariantLong(int returnValue) {
checkNe(returnValue);
}
@Test
@Arguments(setup = "setup")
@IR(counts = {IRNode.SUB_I, "1"})
public int notEqualsVariantSubInvariantInt(int inv1, int inv2, int size) {
int i = 0;
for (; i < 500; ++i) {
blackhole();
// Reassociate to `inv2 - inv1 != i`
if (i - inv2 != -inv1) {
break;
}
}
return i;
}
@Check(test = "notEqualsVariantSubInvariantInt")
public void checkNotEqualsVariantSubInvariantInt(int returnValue) {
checkNe(returnValue);
}
@Test
@Arguments(setup = "setup")
@IR(counts = {IRNode.SUB_L, "1"})
public int notEqualsVariantSubInvariantLong(long inv1, long inv2, int size) {
int i = 0;
for (; i < size; ++i) {
blackhole();
// Reassociate to `inv1 - inv1 != i`
if (i - inv2 != -inv1) {
break;
}
}
return i;
}
@Check(test = "notEqualsVariantSubInvariantLong")
public void checkNotEqualsVariantSubInvariantLong(int returnValue) {
checkNe(returnValue);
}
@Test
@Arguments(setup = "setup")
@IR(failOn = {IRNode.SUB_I})
public int ltDontReassociate(int inv1, int inv2, int size) {
int i = 0;
for (; i < size; ++i) {
blackhole();
if (inv1 + i < inv2) {
break;
}
}
return i;
}
@Check(test = "ltDontReassociate")
public void checkLtDontReassociate(int returnValue) {
int sum = inv1 + returnValue;
if ((returnValue < size && sum >= inv2) || (returnValue > size && sum < inv2)) {
fail(returnValue);
}
}
@Test
@Arguments(setup = "setup")
@IR(failOn = {IRNode.SUB_I})
public int leDontReassociate(int inv1, int inv2, int size) {
int i = 0;
for (; i < size; ++i) {
blackhole();
if (inv1 + i <= inv2) {
break;
}
}
return i;
}
@Check(test = "leDontReassociate")
public void checkLeDontReassociate(int returnValue) {
int sum = inv1 + returnValue;
if ((returnValue < size && sum > inv2) || (returnValue > size && sum <= inv2)) {
fail(returnValue);
}
}
@Test
@Arguments(setup = "setup")
@IR(failOn = {IRNode.SUB_I})
public int gtDontReassociate(int inv1, int inv2, int size) {
int i = 0;
for (; i < size; ++i) {
blackhole();
if (inv1 + i > inv2) {
break;
}
}
return i;
}
@Check(test = "gtDontReassociate")
public void checkGtDontReassociate(int returnValue) {
int sum = inv1 + returnValue;
if ((returnValue < size && sum <= inv2) || (returnValue > size && sum > inv2)) {
fail(returnValue);
}
}
@Test
@Arguments(setup = "setup")
@IR(failOn = {IRNode.SUB_I})
public int geDontReassociate(int inv1, int inv2, int size) {
int i = 0;
for (; i < size; ++i) {
blackhole();
if (inv1 + i >= inv2) {
break;
}
}
return i;
}
@Check(test = "geDontReassociate")
public void checkGeDontReassociate(int returnValue) {
int sum = inv1 + returnValue;
if ((returnValue < size && sum < inv2) || (returnValue > size && sum >= inv2)) {
fail(returnValue);
}
}
}