8323220: Reassociate loop invariants involved in Cmps and Add/Subs
Reviewed-by: epeter, xliu, chagedorn
This commit is contained in:
parent
a293bdff91
commit
140f56718b
@ -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:
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user