8276673: Optimize abs operations in C2 compiler
Reviewed-by: thartmann, jiefu
This commit is contained in:
parent
fef8f2d300
commit
c6196662b8
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2022, 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
|
||||
@ -1847,6 +1847,64 @@ bool BoolNode::is_counted_loop_exit_test() {
|
||||
return false;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//------------------------------Value------------------------------------------
|
||||
const Type* AbsNode::Value(PhaseGVN* phase) const {
|
||||
const Type* t1 = phase->type(in(1));
|
||||
if (t1 == Type::TOP) return Type::TOP;
|
||||
|
||||
switch (t1->base()) {
|
||||
case Type::Int: {
|
||||
const TypeInt* ti = t1->is_int();
|
||||
if (ti->is_con()) {
|
||||
return TypeInt::make(uabs(ti->get_con()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Type::Long: {
|
||||
const TypeLong* tl = t1->is_long();
|
||||
if (tl->is_con()) {
|
||||
return TypeLong::make(uabs(tl->get_con()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Type::FloatCon:
|
||||
return TypeF::make(abs(t1->getf()));
|
||||
case Type::DoubleCon:
|
||||
return TypeD::make(abs(t1->getd()));
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return bottom_type();
|
||||
}
|
||||
|
||||
//------------------------------Identity----------------------------------------
|
||||
Node* AbsNode::Identity(PhaseGVN* phase) {
|
||||
Node* in1 = in(1);
|
||||
// No need to do abs for non-negative values
|
||||
if (phase->type(in1)->higher_equal(TypeInt::POS) ||
|
||||
phase->type(in1)->higher_equal(TypeLong::POS)) {
|
||||
return in1;
|
||||
}
|
||||
// Convert "abs(abs(x))" into "abs(x)"
|
||||
if (in1->Opcode() == Opcode()) {
|
||||
return in1;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
//------------------------------Ideal------------------------------------------
|
||||
Node* AbsNode::Ideal(PhaseGVN* phase, bool can_reshape) {
|
||||
Node* in1 = in(1);
|
||||
// Convert "abs(0-x)" into "abs(x)"
|
||||
if (in1->is_Sub() && phase->type(in1->in(1))->is_zero_type()) {
|
||||
set_req_X(1, in1->in(2), phase);
|
||||
return this;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//------------------------------Value------------------------------------------
|
||||
// Compute sqrt
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2022, 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
|
||||
@ -347,6 +347,9 @@ public:
|
||||
class AbsNode : public Node {
|
||||
public:
|
||||
AbsNode( Node *value ) : Node(0,value) {}
|
||||
virtual Node* Identity(PhaseGVN* phase);
|
||||
virtual Node* Ideal(PhaseGVN* phase, bool can_reshape);
|
||||
virtual const Type* Value(PhaseGVN* phase) const;
|
||||
};
|
||||
|
||||
//------------------------------AbsINode---------------------------------------
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2022, 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
|
||||
@ -593,7 +593,7 @@ public:
|
||||
|
||||
// Check for single integer
|
||||
bool is_con() const { return _lo==_hi; }
|
||||
bool is_con(int i) const { return is_con() && _lo == i; }
|
||||
bool is_con(jint i) const { return is_con() && _lo == i; }
|
||||
jint get_con() const { assert(is_con(), "" ); return _lo; }
|
||||
|
||||
virtual bool is_finite() const; // Has a finite value
|
||||
@ -661,7 +661,7 @@ public:
|
||||
|
||||
// Check for single integer
|
||||
bool is_con() const { return _lo==_hi; }
|
||||
bool is_con(int i) const { return is_con() && _lo == i; }
|
||||
bool is_con(jlong i) const { return is_con() && _lo == i; }
|
||||
jlong get_con() const { assert(is_con(), "" ); return _lo; }
|
||||
|
||||
// Check for positive 32-bit value.
|
||||
|
231
test/hotspot/jtreg/compiler/c2/irTests/TestIRAbs.java
Normal file
231
test/hotspot/jtreg/compiler/c2/irTests/TestIRAbs.java
Normal file
@ -0,0 +1,231 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Arm Limited. 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.*;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8276673
|
||||
* @summary Test abs nodes optimization in C2.
|
||||
* @library /test/lib /
|
||||
* @run driver compiler.c2.irTests.TestIRAbs
|
||||
*/
|
||||
|
||||
public class TestIRAbs {
|
||||
|
||||
public static char [] cspecial = {
|
||||
0, 42, 128, 256, 1024, 4096, 65535
|
||||
};
|
||||
|
||||
public static int [] ispecial = {
|
||||
0, Integer.MAX_VALUE, Integer.MIN_VALUE, -42, 42, -1, 1
|
||||
};
|
||||
|
||||
public static long [] lspecial = {
|
||||
0, Long.MAX_VALUE, Long.MIN_VALUE, -42, 42, -1, 1
|
||||
};
|
||||
|
||||
public static float [] fspecial = {
|
||||
0.0f,
|
||||
-0.0f,
|
||||
Float.MAX_VALUE,
|
||||
Float.MIN_VALUE,
|
||||
-Float.MAX_VALUE,
|
||||
-Float.MIN_VALUE,
|
||||
Float.NaN,
|
||||
Float.POSITIVE_INFINITY,
|
||||
Float.NEGATIVE_INFINITY,
|
||||
Integer.MAX_VALUE,
|
||||
Integer.MIN_VALUE,
|
||||
Long.MAX_VALUE,
|
||||
Long.MIN_VALUE,
|
||||
-1.0f,
|
||||
1.0f,
|
||||
-42.0f,
|
||||
42.0f
|
||||
};
|
||||
|
||||
public static double [] dspecial = {
|
||||
0.0,
|
||||
-0.0,
|
||||
Double.MAX_VALUE,
|
||||
Double.MIN_VALUE,
|
||||
-Double.MAX_VALUE,
|
||||
-Double.MIN_VALUE,
|
||||
Double.NaN,
|
||||
Double.POSITIVE_INFINITY,
|
||||
Double.NEGATIVE_INFINITY,
|
||||
Integer.MAX_VALUE,
|
||||
Integer.MIN_VALUE,
|
||||
Long.MIN_VALUE,
|
||||
Long.MAX_VALUE,
|
||||
-1,
|
||||
1,
|
||||
42,
|
||||
-42,
|
||||
Math.PI,
|
||||
Math.E,
|
||||
Float.MAX_VALUE,
|
||||
Float.MIN_VALUE,
|
||||
-Float.MAX_VALUE,
|
||||
-Float.MIN_VALUE,
|
||||
Float.NaN,
|
||||
Float.POSITIVE_INFINITY,
|
||||
Float.NEGATIVE_INFINITY
|
||||
};
|
||||
|
||||
public static void main(String[] args) {
|
||||
TestFramework.run();
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(failOn = {IRNode.ABS_I, IRNode.ABS_L, IRNode.ABS_F, IRNode.ABS_D})
|
||||
public void testAbsConstant() {
|
||||
// Test abs(constant) optimization for int
|
||||
Asserts.assertEquals(Integer.MAX_VALUE, Math.abs(Integer.MAX_VALUE));
|
||||
Asserts.assertEquals(Integer.MIN_VALUE, Math.abs(Integer.MIN_VALUE));
|
||||
Asserts.assertEquals(Integer.MAX_VALUE, Math.abs(-Integer.MAX_VALUE));
|
||||
|
||||
// Test abs(constant) optimization for long
|
||||
Asserts.assertEquals(Long.MAX_VALUE, Math.abs(Long.MAX_VALUE));
|
||||
Asserts.assertEquals(Long.MIN_VALUE, Math.abs(Long.MIN_VALUE));
|
||||
Asserts.assertEquals(Long.MAX_VALUE, Math.abs(-Long.MAX_VALUE));
|
||||
|
||||
// Test abs(constant) optimization for float
|
||||
Asserts.assertTrue(Float.isNaN(Math.abs(Float.NaN)));
|
||||
Asserts.assertEquals(Float.POSITIVE_INFINITY, Math.abs(Float.NEGATIVE_INFINITY));
|
||||
Asserts.assertEquals(Float.POSITIVE_INFINITY, Math.abs(Float.POSITIVE_INFINITY));
|
||||
Asserts.assertEquals(0.0f, Math.abs(0.0f));
|
||||
Asserts.assertEquals(0.0f, Math.abs(-0.0f));
|
||||
Asserts.assertEquals(Float.MAX_VALUE, Math.abs(Float.MAX_VALUE));
|
||||
Asserts.assertEquals(Float.MIN_VALUE, Math.abs(Float.MIN_VALUE));
|
||||
Asserts.assertEquals(Float.MAX_VALUE, Math.abs(-Float.MAX_VALUE));
|
||||
Asserts.assertEquals(Float.MIN_VALUE, Math.abs(-Float.MIN_VALUE));
|
||||
|
||||
// Test abs(constant) optimization for double
|
||||
Asserts.assertTrue(Double.isNaN(Math.abs(Double.NaN)));
|
||||
Asserts.assertEquals(Double.POSITIVE_INFINITY, Math.abs(Double.NEGATIVE_INFINITY));
|
||||
Asserts.assertEquals(Double.POSITIVE_INFINITY, Math.abs(Double.POSITIVE_INFINITY));
|
||||
Asserts.assertEquals(0.0, Math.abs(0.0));
|
||||
Asserts.assertEquals(0.0, Math.abs(-0.0));
|
||||
Asserts.assertEquals(Double.MAX_VALUE, Math.abs(Double.MAX_VALUE));
|
||||
Asserts.assertEquals(Double.MIN_VALUE, Math.abs(Double.MIN_VALUE));
|
||||
Asserts.assertEquals(Double.MAX_VALUE, Math.abs(-Double.MAX_VALUE));
|
||||
Asserts.assertEquals(Double.MIN_VALUE, Math.abs(-Double.MIN_VALUE));
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(counts = {IRNode.ABS_I, "1"})
|
||||
public int testInt0(int x) {
|
||||
return Math.abs(Math.abs(x)); // transformed to Math.abs(x)
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(failOn = {IRNode.SUB_I})
|
||||
@IR(counts = {IRNode.ABS_I, "1"})
|
||||
public int testInt1(int x) {
|
||||
return Math.abs(0 - x); // transformed to Math.abs(x)
|
||||
}
|
||||
|
||||
@Run(test = {"testInt0", "testInt1"})
|
||||
public void checkTestInt(RunInfo info) {
|
||||
for (int i = 0; i < ispecial.length; i++) {
|
||||
Asserts.assertEquals(Math.abs(ispecial[i]), testInt0(ispecial[i]));
|
||||
Asserts.assertEquals(Math.abs(ispecial[i]), testInt1(ispecial[i]));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(counts = {IRNode.ABS_L, "1"})
|
||||
public long testLong0(long x) {
|
||||
return Math.abs(Math.abs(x)); // transformed to Math.abs(x)
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(failOn = {IRNode.SUB_L})
|
||||
@IR(counts = {IRNode.ABS_L, "1"})
|
||||
public long testLong1(long x) {
|
||||
return Math.abs(0 - x); // transformed to Math.abs(x)
|
||||
}
|
||||
|
||||
@Run(test = {"testLong0", "testLong1"})
|
||||
public void checkTestLong(RunInfo info) {
|
||||
for (int i = 0; i < lspecial.length; i++) {
|
||||
Asserts.assertEquals(Math.abs(lspecial[i]), testLong0(lspecial[i]));
|
||||
Asserts.assertEquals(Math.abs(lspecial[i]), testLong1(lspecial[i]));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(counts = {IRNode.ABS_F, "1"})
|
||||
public float testFloat0(float x) {
|
||||
return Math.abs(Math.abs(x)); // transformed to Math.abs(x)
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(failOn = {IRNode.SUB_F})
|
||||
@IR(counts = {IRNode.ABS_F, "1"})
|
||||
public float testFloat1(float x) {
|
||||
return Math.abs(0 - x); // transformed to Math.abs(x)
|
||||
}
|
||||
|
||||
@Run(test = {"testFloat0", "testFloat1"})
|
||||
public void checkTestFloat(RunInfo info) {
|
||||
for (int i = 0; i < fspecial.length; i++) {
|
||||
Asserts.assertEquals(Math.abs(fspecial[i]), testFloat0(fspecial[i]));
|
||||
Asserts.assertEquals(Math.abs(fspecial[i]), testFloat1(fspecial[i]));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(counts = {IRNode.ABS_D, "1"})
|
||||
public double testDouble0(double x) {
|
||||
return Math.abs(Math.abs(x)); // transformed to Math.abs(x)
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(failOn = {IRNode.SUB_D})
|
||||
@IR(counts = {IRNode.ABS_D, "1"})
|
||||
public double testDouble1(double x) {
|
||||
return Math.abs(0 - x); // transformed to Math.abs(x)
|
||||
}
|
||||
|
||||
@Run(test = {"testDouble0", "testDouble1"})
|
||||
public void checkTestDouble(RunInfo info) {
|
||||
for (int i = 0; i < dspecial.length; i++) {
|
||||
Asserts.assertEquals(Math.abs(dspecial[i]), testDouble0(dspecial[i]));
|
||||
Asserts.assertEquals(Math.abs(dspecial[i]), testDouble1(dspecial[i]));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(failOn = {IRNode.ABS_I})
|
||||
public void testChar() {
|
||||
for (int i = 0; i < cspecial.length; i++) {
|
||||
Asserts.assertEquals(cspecial[i], (char) Math.abs(cspecial[i]));
|
||||
}
|
||||
}
|
||||
}
|
@ -136,6 +136,10 @@ public class IRNode {
|
||||
public static final String SCOPE_OBJECT = "(.*# ScObj.*" + END;
|
||||
public static final String MEMBAR = START + "MemBar" + MID + END;
|
||||
|
||||
public static final String ABS_I = START + "AbsI" + MID + END;
|
||||
public static final String ABS_L = START + "AbsL" + MID + END;
|
||||
public static final String ABS_F = START + "AbsF" + MID + END;
|
||||
public static final String ABS_D = START + "AbsD" + MID + END;
|
||||
public static final String AND_I = START + "AndI" + MID + END;
|
||||
public static final String AND_L = START + "AndL" + MID + END;
|
||||
public static final String LSHIFT_I = START + "LShiftI" + MID + END;
|
||||
@ -145,6 +149,8 @@ public class IRNode {
|
||||
public static final String ADD_VD = START + "AddVD" + MID + END;
|
||||
public static final String SUB_I = START + "SubI" + MID + END;
|
||||
public static final String SUB_L = START + "SubL" + MID + END;
|
||||
public static final String SUB_F = START + "SubF" + MID + END;
|
||||
public static final String SUB_D = START + "SubD" + MID + END;
|
||||
public static final String MUL_I = START + "MulI" + MID + END;
|
||||
public static final String MUL_L = START + "MulL" + MID + END;
|
||||
public static final String CONV_I2L = START + "ConvI2L" + MID + END;
|
||||
|
Loading…
Reference in New Issue
Block a user