8324655: Identify integer minimum and maximum patterns created with if statements
Reviewed-by: epeter, qamai
This commit is contained in:
parent
c7b9dc463a
commit
9f920b9bbf
@ -1080,7 +1080,7 @@ const Type* XorLNode::Value(PhaseGVN* phase) const {
|
||||
return AddNode::Value(phase);
|
||||
}
|
||||
|
||||
static Node* build_min_max_int(Node* a, Node* b, bool is_max) {
|
||||
Node* MaxNode::build_min_max_int(Node* a, Node* b, bool is_max) {
|
||||
if (is_max) {
|
||||
return new MaxINode(a, b);
|
||||
} else {
|
||||
@ -1088,6 +1088,14 @@ static Node* build_min_max_int(Node* a, Node* b, bool is_max) {
|
||||
}
|
||||
}
|
||||
|
||||
Node* MaxNode::build_min_max_long(PhaseGVN* phase, Node* a, Node* b, bool is_max) {
|
||||
if (is_max) {
|
||||
return new MaxLNode(phase->C, a, b);
|
||||
} else {
|
||||
return new MinLNode(phase->C, a, b);
|
||||
}
|
||||
}
|
||||
|
||||
Node* MaxNode::build_min_max(Node* a, Node* b, bool is_max, bool is_unsigned, const Type* t, PhaseGVN& gvn) {
|
||||
bool is_int = gvn.type(a)->isa_int();
|
||||
assert(is_int || gvn.type(a)->isa_long(), "int or long inputs");
|
||||
|
@ -295,6 +295,9 @@ public:
|
||||
static Node* min_diff_with_zero(Node* a, Node* b, const Type* t, PhaseGVN& gvn) {
|
||||
return build_min_max_diff_with_zero(a, b, false, t, gvn);
|
||||
}
|
||||
|
||||
static Node* build_min_max_int(Node* a, Node* b, bool is_max);
|
||||
static Node* build_min_max_long(PhaseGVN* phase, Node* a, Node* b, bool is_max);
|
||||
};
|
||||
|
||||
//------------------------------MaxINode---------------------------------------
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2024, 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
|
||||
@ -96,6 +96,12 @@ Node *CMoveNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||
BoolNode* b = in(Condition)->as_Bool()->negate(phase);
|
||||
return make(in(Control), phase->transform(b), in(IfTrue), in(IfFalse), _type);
|
||||
}
|
||||
|
||||
Node* minmax = Ideal_minmax(phase, this);
|
||||
if (minmax != nullptr) {
|
||||
return minmax;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -185,6 +191,65 @@ CMoveNode *CMoveNode::make(Node *c, Node *bol, Node *left, Node *right, const Ty
|
||||
}
|
||||
}
|
||||
|
||||
// Try to identify min/max patterns in CMoves
|
||||
Node* CMoveNode::Ideal_minmax(PhaseGVN* phase, CMoveNode* cmove) {
|
||||
// If we're post loop opts then don't attempt to match the min/max pattern, as this node might have been a
|
||||
// MinL or MaxL that was already expanded during macro expansion.
|
||||
if (phase->C->post_loop_opts_phase()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// The BoolNode may have been idealized into a constant. If that's the case, then Identity should take care of it instead.
|
||||
BoolNode* bol = cmove->in(CMoveNode::Condition)->isa_Bool();
|
||||
if (bol == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Node* cmp = bol->in(1);
|
||||
int cmove_op = cmove->Opcode();
|
||||
int cmp_op = cmp->Opcode();
|
||||
|
||||
// Ensure comparison is an integral type, and that the cmove is of the same type.
|
||||
if (!((cmp_op == Op_CmpI && cmove_op == Op_CMoveI) || (cmp_op == Op_CmpL && cmove_op == Op_CMoveL))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Only accept canonicalized le and lt comparisons
|
||||
int test = bol->_test._test;
|
||||
if (test != BoolTest::le && test != BoolTest::lt) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// The values being compared
|
||||
Node* cmp_l = cmp->in(1);
|
||||
Node* cmp_r = cmp->in(2);
|
||||
|
||||
// The values being selected
|
||||
Node* cmove_l = cmove->in(CMoveNode::IfTrue);
|
||||
Node* cmove_r = cmove->in(CMoveNode::IfFalse);
|
||||
|
||||
// For this transformation to be valid, the values being compared must be the same as the values being selected.
|
||||
// We accept two different forms, "a < b ? a : b" and "a < b ? b : a". For the first form, the lhs and rhs of the
|
||||
// comparison and cmove are the same, resulting in a minimum. For the second form, the lhs and rhs of both are flipped,
|
||||
// resulting in a maximum. If neither form is found, bail out.
|
||||
|
||||
bool is_max;
|
||||
if (cmp_l == cmove_l && cmp_r == cmove_r) {
|
||||
is_max = false;
|
||||
} else if (cmp_l == cmove_r && cmp_r == cmove_l) {
|
||||
is_max = true;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Create the Min/Max node based on the type and kind
|
||||
if (cmp_op == Op_CmpL) {
|
||||
return MaxNode::build_min_max_long(phase, cmp_l, cmp_r, is_max);
|
||||
} else {
|
||||
return MaxNode::build_min_max_int(cmp_l, cmp_r, is_max);
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//------------------------------Ideal------------------------------------------
|
||||
// Return a node which is more "ideal" than the current node.
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2024, 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
|
||||
@ -49,7 +49,8 @@ class CMoveNode : public TypeNode {
|
||||
virtual Node* Identity(PhaseGVN* phase);
|
||||
static CMoveNode *make(Node *c, Node *bol, Node *left, Node *right, const Type *t);
|
||||
// Helper function to spot cmove graph shapes
|
||||
static Node *is_cmove_id( PhaseTransform *phase, Node *cmp, Node *t, Node *f, BoolNode *b );
|
||||
static Node* is_cmove_id(PhaseTransform* phase, Node* cmp, Node* t, Node* f, BoolNode* b);
|
||||
static Node* Ideal_minmax(PhaseGVN* phase, CMoveNode* cmov);
|
||||
};
|
||||
|
||||
//------------------------------CMoveDNode-------------------------------------
|
||||
|
489
test/hotspot/jtreg/compiler/c2/irTests/TestIfMinMax.java
Normal file
489
test/hotspot/jtreg/compiler/c2/irTests/TestIfMinMax.java
Normal file
@ -0,0 +1,489 @@
|
||||
/*
|
||||
* Copyright (c) 2024, 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.
|
||||
*/
|
||||
|
||||
package compiler.c2.irTests;
|
||||
|
||||
import jdk.test.lib.Asserts;
|
||||
import compiler.lib.ir_framework.*;
|
||||
import java.util.Random;
|
||||
import jdk.test.lib.Utils;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8324655
|
||||
* @summary Test that if expressions are properly folded into min/max nodes
|
||||
* @library /test/lib /
|
||||
* @run main compiler.c2.irTests.TestIfMinMax
|
||||
*/
|
||||
public class TestIfMinMax {
|
||||
private static final Random RANDOM = Utils.getRandomInstance();
|
||||
|
||||
public static void main(String[] args) {
|
||||
TestFramework.run();
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(failOn = { IRNode.IF }, counts = { IRNode.MIN_I, "1" })
|
||||
public int testMinI1(int a, int b) {
|
||||
return a < b ? a : b;
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(failOn = { IRNode.IF }, counts = { IRNode.MIN_I, "1" })
|
||||
public int testMinI2(int a, int b) {
|
||||
return a > b ? b : a;
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(failOn = { IRNode.IF }, counts = { IRNode.MAX_I, "1" })
|
||||
public int testMaxI1(int a, int b) {
|
||||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(failOn = { IRNode.IF }, counts = { IRNode.MAX_I, "1" })
|
||||
public int testMaxI2(int a, int b) {
|
||||
return a < b ? b : a;
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(failOn = { IRNode.IF }, counts = { IRNode.MIN_I, "1" })
|
||||
public int testMinI1E(int a, int b) {
|
||||
return a <= b ? a : b;
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(failOn = { IRNode.IF }, counts = { IRNode.MIN_I, "1" })
|
||||
public int testMinI2E(int a, int b) {
|
||||
return a >= b ? b : a;
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(failOn = { IRNode.IF }, counts = { IRNode.MAX_I, "1" })
|
||||
public int testMaxI1E(int a, int b) {
|
||||
return a >= b ? a : b;
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(failOn = { IRNode.IF }, counts = { IRNode.MAX_I, "1" })
|
||||
public int testMaxI2E(int a, int b) {
|
||||
return a <= b ? b : a;
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(phase = { CompilePhase.BEFORE_MACRO_EXPANSION }, failOn = { IRNode.IF }, counts = { IRNode.MIN_L, "1" })
|
||||
public long testMinL1(long a, long b) {
|
||||
return a < b ? a : b;
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(phase = { CompilePhase.BEFORE_MACRO_EXPANSION }, failOn = { IRNode.IF }, counts = { IRNode.MIN_L, "1" })
|
||||
public long testMinL2(long a, long b) {
|
||||
return a > b ? b : a;
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(phase = { CompilePhase.BEFORE_MACRO_EXPANSION }, failOn = { IRNode.IF }, counts = { IRNode.MAX_L, "1" })
|
||||
public long testMaxL1(long a, long b) {
|
||||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(phase = { CompilePhase.BEFORE_MACRO_EXPANSION }, failOn = { IRNode.IF }, counts = { IRNode.MAX_L, "1" })
|
||||
public long testMaxL2(long a, long b) {
|
||||
return a < b ? b : a;
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(phase = { CompilePhase.BEFORE_MACRO_EXPANSION }, failOn = { IRNode.IF }, counts = { IRNode.MIN_L, "1" })
|
||||
public long testMinL1E(long a, long b) {
|
||||
return a <= b ? a : b;
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(phase = { CompilePhase.BEFORE_MACRO_EXPANSION }, failOn = { IRNode.IF }, counts = { IRNode.MIN_L, "1" })
|
||||
public long testMinL2E(long a, long b) {
|
||||
return a >= b ? b : a;
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(phase = { CompilePhase.BEFORE_MACRO_EXPANSION }, failOn = { IRNode.IF }, counts = { IRNode.MAX_L, "1" })
|
||||
public long testMaxL1E(long a, long b) {
|
||||
return a >= b ? a : b;
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(phase = { CompilePhase.BEFORE_MACRO_EXPANSION }, failOn = { IRNode.IF }, counts = { IRNode.MAX_L, "1" })
|
||||
public long testMaxL2E(long a, long b) {
|
||||
return a <= b ? b : a;
|
||||
}
|
||||
|
||||
@Setup
|
||||
static Object[] setupIntArrays() {
|
||||
int[] a = new int[512];
|
||||
int[] b = new int[512];
|
||||
|
||||
for (int i = 0; i < 512; i++) {
|
||||
a[i] = RANDOM.nextInt();
|
||||
b[i] = RANDOM.nextInt();
|
||||
}
|
||||
|
||||
return new Object[] { a, b };
|
||||
}
|
||||
|
||||
@Setup
|
||||
static Object[] setupLongArrays() {
|
||||
long[] a = new long[512];
|
||||
long[] b = new long[512];
|
||||
|
||||
for (int i = 0; i < 512; i++) {
|
||||
a[i] = RANDOM.nextLong();
|
||||
b[i] = RANDOM.nextLong();
|
||||
}
|
||||
|
||||
return new Object[] { a, b };
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(applyIf = { "SuperWordReductions", "true" },
|
||||
applyIfCPUFeatureOr = { "sse4.1", "true" , "asimd" , "true"},
|
||||
counts = { IRNode.MAX_REDUCTION_V, "> 0" })
|
||||
@Arguments(setup = "setupIntArrays")
|
||||
public Object[] testMaxIntReduction(int[] a, int[] b) {
|
||||
int r = 0;
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
int aI = a[i] * 2;
|
||||
|
||||
r = aI > r ? aI : r;
|
||||
}
|
||||
|
||||
return new Object[] { a, r };
|
||||
}
|
||||
|
||||
@Check(test = "testMaxIntReduction")
|
||||
public void checkTestMaxIntReduction(Object[] vals) {
|
||||
int[] a = (int[]) vals[0];
|
||||
int testRet = (int) vals[1];
|
||||
|
||||
int r = 0;
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
int aI = a[i] * 2;
|
||||
|
||||
r = aI > r ? aI : r;
|
||||
}
|
||||
|
||||
if (r != testRet) {
|
||||
throw new IllegalStateException("Int max reduction test failed: expected " + testRet + " but got " + r);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(applyIf = { "SuperWordReductions", "true" },
|
||||
applyIfCPUFeatureOr = { "sse4.1", "true" , "asimd" , "true"},
|
||||
counts = { IRNode.MIN_REDUCTION_V, "> 0" })
|
||||
@Arguments(setup = "setupIntArrays")
|
||||
public Object[] testMinIntReduction(int[] a, int[] b) {
|
||||
int r = 0;
|
||||
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
int aI = a[i] * 2;
|
||||
|
||||
r = aI < r ? aI : r;
|
||||
}
|
||||
|
||||
return new Object[] { a, r };
|
||||
}
|
||||
|
||||
@Check(test = "testMinIntReduction")
|
||||
public void checkTestMinIntReduction(Object[] vals) {
|
||||
int[] a = (int[]) vals[0];
|
||||
int testRet = (int) vals[1];
|
||||
|
||||
int r = 0;
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
int aI = a[i] * 2;
|
||||
|
||||
r = aI < r ? aI : r;
|
||||
}
|
||||
|
||||
if (r != testRet) {
|
||||
throw new IllegalStateException("Int min reduction test failed: expected " + testRet + " but got " + r);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(applyIf = { "SuperWordReductions", "true" },
|
||||
applyIfCPUFeatureOr = { "avx512", "true" },
|
||||
counts = { IRNode.MAX_REDUCTION_V, "> 0" })
|
||||
@Arguments(setup = "setupLongArrays")
|
||||
public Object[] testMaxLongReduction(long[] a, long[] b) {
|
||||
long r = 0;
|
||||
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
long aI = a[i] * 2;
|
||||
|
||||
r = aI > r ? aI : r;
|
||||
}
|
||||
|
||||
return new Object[] { a, r };
|
||||
}
|
||||
|
||||
@Check(test = "testMaxLongReduction")
|
||||
public void checkTestMaxLongReduction(Object[] vals) {
|
||||
long[] a = (long[]) vals[0];
|
||||
long testRet = (long) vals[1];
|
||||
|
||||
long r = 0;
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
long aI = a[i] * 2;
|
||||
|
||||
r = aI > r ? aI : r;
|
||||
}
|
||||
|
||||
if (r != testRet) {
|
||||
throw new IllegalStateException("Long max reduction test failed: expected " + testRet + " but got " + r);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(applyIf = { "SuperWordReductions", "true" },
|
||||
applyIfCPUFeatureOr = { "avx512", "true" },
|
||||
counts = { IRNode.MIN_REDUCTION_V, "> 0" })
|
||||
@Arguments(setup = "setupLongArrays")
|
||||
public Object[] testMinLongReduction(long[] a, long[] b) {
|
||||
long r = 0;
|
||||
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
long aI = a[i] * 2;
|
||||
|
||||
r = aI < r ? aI : r;
|
||||
}
|
||||
|
||||
return new Object[] { a, r };
|
||||
}
|
||||
|
||||
@Check(test = "testMinLongReduction")
|
||||
public void checkTestMinLongReduction(Object[] vals) {
|
||||
long[] a = (long[]) vals[0];
|
||||
long testRet = (long) vals[1];
|
||||
|
||||
long r = 0;
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
long aI = a[i] * 2;
|
||||
|
||||
r = aI < r ? aI : r;
|
||||
}
|
||||
|
||||
if (r != testRet) {
|
||||
throw new IllegalStateException("Long min reduction test failed: expected " + testRet + " but got " + r);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(applyIfCPUFeatureOr = { "sse4.1", "true" , "asimd" , "true"},
|
||||
counts = { IRNode.MAX_VI, "> 0" })
|
||||
@Arguments(setup = "setupIntArrays")
|
||||
public Object[] testMaxIntVector(int[] a, int[] b) {
|
||||
int[] r = new int[a.length];
|
||||
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
int aI = a[i];
|
||||
int bI = b[i];
|
||||
|
||||
r[i] = aI > bI ? aI : bI;
|
||||
}
|
||||
|
||||
return new Object[] { a, b, r };
|
||||
}
|
||||
|
||||
@Check(test = "testMaxIntVector")
|
||||
public void checkTestMaxIntVector(Object[] vals) {
|
||||
int[] a = (int[]) vals[0];
|
||||
int[] b = (int[]) vals[1];
|
||||
int[] testRet = (int[]) vals[2];
|
||||
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
int aI = a[i];
|
||||
int bI = b[i];
|
||||
|
||||
int r = aI > bI ? aI : bI;
|
||||
|
||||
if (r != testRet[i]) {
|
||||
throw new IllegalStateException("Int max vectorization test failed: expected " + testRet + " but got " + r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(applyIfCPUFeatureOr = { "sse4.1", "true" , "asimd" , "true"},
|
||||
counts = { IRNode.MIN_VI, "> 0" })
|
||||
@Arguments(setup = "setupIntArrays")
|
||||
public Object[] testMinIntVector(int[] a, int[] b) {
|
||||
int[] r = new int[a.length];
|
||||
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
int aI = a[i];
|
||||
int bI = b[i];
|
||||
|
||||
r[i] = aI < bI ? aI : bI;
|
||||
}
|
||||
|
||||
return new Object[] { a, b, r };
|
||||
}
|
||||
|
||||
@Check(test = "testMinIntVector")
|
||||
public void checkTestMinIntVector(Object[] vals) {
|
||||
int[] a = (int[]) vals[0];
|
||||
int[] b = (int[]) vals[1];
|
||||
int[] testRet = (int[]) vals[2];
|
||||
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
int aI = a[i];
|
||||
int bI = b[i];
|
||||
|
||||
int r = aI < bI ? aI : bI;
|
||||
|
||||
if (r != testRet[i]) {
|
||||
throw new IllegalStateException("Int min vectorization test failed: expected " + testRet + " but got " + r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(applyIfCPUFeatureOr = { "sse4.1", "true" , "asimd" , "true"},
|
||||
counts = { IRNode.MAX_VL, "> 0" })
|
||||
@Arguments(setup = "setupLongArrays")
|
||||
public Object[] testMaxLongVector(long[] a, long[] b) {
|
||||
long[] r = new long[a.length];
|
||||
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
long aI = a[i];
|
||||
long bI = b[i];
|
||||
|
||||
r[i] = aI > bI ? aI : bI;
|
||||
}
|
||||
|
||||
return new Object[] { a, b, r };
|
||||
}
|
||||
|
||||
@Check(test = "testMaxLongVector")
|
||||
public void checkTestMaxLongVector(Object[] vals) {
|
||||
long[] a = (long[]) vals[0];
|
||||
long[] b = (long[]) vals[1];
|
||||
long[] testRet = (long[]) vals[2];
|
||||
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
long aI = a[i];
|
||||
long bI = b[i];
|
||||
|
||||
long r = aI > bI ? aI : bI;
|
||||
|
||||
if (r != testRet[i]) {
|
||||
throw new IllegalStateException("Long max vectorization test failed: expected " + testRet + " but got " + r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(applyIfCPUFeatureOr = { "sse4.1", "true" , "asimd" , "true"},
|
||||
counts = { IRNode.MIN_VL, "> 0" })
|
||||
@Arguments(setup = "setupLongArrays")
|
||||
public Object[] testMinLongVector(long[] a, long[] b) {
|
||||
long[] r = new long[a.length];
|
||||
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
long aI = a[i];
|
||||
long bI = b[i];
|
||||
|
||||
r[i] = aI < bI ? aI : bI;
|
||||
}
|
||||
|
||||
return new Object[] { a, b, r };
|
||||
}
|
||||
|
||||
@Check(test = "testMinLongVector")
|
||||
public void checkTestMinLongVector(Object[] vals) {
|
||||
long[] a = (long[]) vals[0];
|
||||
long[] b = (long[]) vals[1];
|
||||
long[] testRet = (long[]) vals[2];
|
||||
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
long aI = a[i];
|
||||
long bI = b[i];
|
||||
|
||||
long r = aI < bI ? aI : bI;
|
||||
|
||||
if (r != testRet[i]) {
|
||||
throw new IllegalStateException("Long min vectorization test failed: expected " + testRet + " but got " + r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Run(test = { "testMinI1", "testMinI2", "testMaxI1", "testMaxI2", "testMinI1E", "testMinI2E", "testMaxI1E", "testMaxI2E" })
|
||||
public void runTestIntegers() {
|
||||
testIntegers(10, 20);
|
||||
testIntegers(20, 10);
|
||||
testIntegers(10, 10);
|
||||
testIntegers(Integer.MAX_VALUE, Integer.MIN_VALUE);
|
||||
testIntegers(Integer.MIN_VALUE, Integer.MAX_VALUE);
|
||||
testIntegers(RANDOM.nextInt(), RANDOM.nextInt());
|
||||
}
|
||||
|
||||
@DontCompile
|
||||
public void testIntegers(int a, int b) {
|
||||
Asserts.assertEQ(a < b ? a : b, testMinI1(a, b));
|
||||
Asserts.assertEQ(a > b ? b : a, testMinI2(a, b));
|
||||
Asserts.assertEQ(a > b ? a : b, testMaxI1(a, b));
|
||||
Asserts.assertEQ(a < b ? b : a, testMaxI2(a, b));
|
||||
|
||||
Asserts.assertEQ(a <= b ? a : b, testMinI1E(a, b));
|
||||
Asserts.assertEQ(a >= b ? b : a, testMinI2E(a, b));
|
||||
Asserts.assertEQ(a >= b ? a : b, testMaxI1E(a, b));
|
||||
Asserts.assertEQ(a <= b ? b : a, testMaxI2E(a, b));
|
||||
}
|
||||
|
||||
@Run(test = { "testMinL1", "testMinL2", "testMaxL1", "testMaxL2", "testMinL1E", "testMinL2E", "testMaxL1E", "testMaxL2E" })
|
||||
public void runTestLongs() {
|
||||
testLongs(10, 20);
|
||||
testLongs(20, 10);
|
||||
testLongs(10, 10);
|
||||
testLongs(Integer.MAX_VALUE, Integer.MIN_VALUE);
|
||||
testLongs(Integer.MIN_VALUE, Integer.MAX_VALUE);
|
||||
testLongs(Long.MAX_VALUE, Long.MIN_VALUE);
|
||||
testLongs(Long.MIN_VALUE, Long.MAX_VALUE);
|
||||
testLongs(RANDOM.nextLong(), RANDOM.nextLong());
|
||||
}
|
||||
|
||||
@DontCompile
|
||||
public void testLongs(long a, long b) {
|
||||
Asserts.assertEQ(a < b ? a : b, testMinL1(a, b));
|
||||
Asserts.assertEQ(a > b ? b : a, testMinL2(a, b));
|
||||
Asserts.assertEQ(a > b ? a : b, testMaxL1(a, b));
|
||||
Asserts.assertEQ(a < b ? b : a, testMaxL2(a, b));
|
||||
|
||||
Asserts.assertEQ(a <= b ? a : b, testMinL1E(a, b));
|
||||
Asserts.assertEQ(a >= b ? b : a, testMinL2E(a, b));
|
||||
Asserts.assertEQ(a >= b ? a : b, testMaxL1E(a, b));
|
||||
Asserts.assertEQ(a <= b ? b : a, testMaxL2E(a, b));
|
||||
}
|
||||
}
|
@ -867,6 +867,11 @@ public class IRNode {
|
||||
vectorNode(MAX_VD, "MaxV", TYPE_DOUBLE);
|
||||
}
|
||||
|
||||
public static final String MAX_VL = VECTOR_PREFIX + "MAX_VL" + POSTFIX;
|
||||
static {
|
||||
vectorNode(MAX_VL, "MaxV", TYPE_LONG);
|
||||
}
|
||||
|
||||
public static final String MEMBAR = PREFIX + "MEMBAR" + POSTFIX;
|
||||
static {
|
||||
beforeMatchingNameRegex(MEMBAR, "MemBar");
|
||||
@ -927,6 +932,11 @@ public class IRNode {
|
||||
vectorNode(MIN_VD, "MinV", TYPE_DOUBLE);
|
||||
}
|
||||
|
||||
public static final String MIN_VL = VECTOR_PREFIX + "MIN_VL" + POSTFIX;
|
||||
static {
|
||||
vectorNode(MIN_VL, "MinV", TYPE_LONG);
|
||||
}
|
||||
|
||||
public static final String MUL = PREFIX + "MUL" + POSTFIX;
|
||||
static {
|
||||
beforeMatchingNameRegex(MUL, "Mul(I|L|F|D)");
|
||||
|
128
test/micro/org/openjdk/bench/vm/compiler/IfMinMax.java
Normal file
128
test/micro/org/openjdk/bench/vm/compiler/IfMinMax.java
Normal file
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (c) 2024, 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.
|
||||
*/
|
||||
|
||||
package org.openjdk.bench.vm.compiler;
|
||||
|
||||
import org.openjdk.jmh.annotations.*;
|
||||
import org.openjdk.jmh.infra.Blackhole;
|
||||
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@BenchmarkMode(Mode.AverageTime)
|
||||
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
||||
@Measurement(iterations = 5, time = 1000, timeUnit = TimeUnit.MILLISECONDS)
|
||||
@Warmup(iterations = 5, time = 1000, timeUnit = TimeUnit.MILLISECONDS)
|
||||
@Fork(3)
|
||||
public class IfMinMax {
|
||||
private static final int SIZE = 10_000;
|
||||
|
||||
@Benchmark
|
||||
public void testSingleInt(Blackhole blackhole, BenchState state) {
|
||||
int a = state.i1[state.random.nextInt(SIZE)];
|
||||
int b = state.i2[state.random.nextInt(SIZE)];
|
||||
blackhole.consume(a > b ? a : b);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void testVectorInt(Blackhole blackhole, BenchState state) {
|
||||
for (int i = 0; i < SIZE; i++) {
|
||||
state.i3[i] = state.i1[i] > state.i2[i] ? state.i1[i] : state.i2[i];
|
||||
}
|
||||
|
||||
blackhole.consume(state.i3);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void testReductionInt(Blackhole blackhole, BenchState state) {
|
||||
int a = 0;
|
||||
|
||||
for (int i = 0; i < SIZE; i++) {
|
||||
if (state.i1[i] > a) {
|
||||
a = state.i1[i];
|
||||
}
|
||||
}
|
||||
|
||||
blackhole.consume(a);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void testSingleLong(Blackhole blackhole, BenchState state) {
|
||||
long a = state.l1[state.random.nextInt(SIZE)];
|
||||
long b = state.l2[state.random.nextInt(SIZE)];
|
||||
blackhole.consume(a > b ? a : b);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void testVectorLong(Blackhole blackhole, BenchState state) {
|
||||
for (int i = 0; i < SIZE; i++) {
|
||||
state.l3[i] = state.l1[i] > state.l2[i] ? state.l1[i] : state.l2[i];
|
||||
}
|
||||
|
||||
blackhole.consume(state.l3);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void testReductionLong(Blackhole blackhole, BenchState state) {
|
||||
long a = 0;
|
||||
|
||||
for (int i = 0; i < SIZE; i++) {
|
||||
if (state.l1[i] > a) {
|
||||
a = state.l1[i];
|
||||
}
|
||||
}
|
||||
|
||||
blackhole.consume(a);
|
||||
}
|
||||
|
||||
@State(Scope.Benchmark)
|
||||
public static class BenchState {
|
||||
private final int[] i1 = new int[SIZE];
|
||||
private final int[] i2 = new int[SIZE];
|
||||
private final int[] i3 = new int[SIZE];
|
||||
|
||||
private final long[] l1 = new long[SIZE];
|
||||
private final long[] l2 = new long[SIZE];
|
||||
private final long[] l3 = new long[SIZE];
|
||||
|
||||
private Random random;
|
||||
|
||||
public BenchState() {
|
||||
}
|
||||
|
||||
@Setup
|
||||
public void setup() {
|
||||
this.random = new Random(1000);
|
||||
|
||||
for (int i = 0; i < SIZE; i++) {
|
||||
i1[i] = this.random.nextInt();
|
||||
i2[i] = this.random.nextInt();
|
||||
i3[i] = this.random.nextInt();
|
||||
|
||||
l1[i] = this.random.nextLong();
|
||||
l2[i] = this.random.nextLong();
|
||||
l3[i] = this.random.nextLong();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user