8263006: Add optimization for Max(*)Node and Min(*)Node
Co-authored-by: Wang Huang <whuang@openjdk.org> Co-authored-by: Wu Yan <wuyan34@huawei.com> Reviewed-by: kvn
This commit is contained in:
parent
16ca370f1a
commit
599d07c0db
@ -62,10 +62,35 @@ Node* AddNode::Identity(PhaseGVN* phase) {
|
||||
|
||||
//------------------------------commute----------------------------------------
|
||||
// Commute operands to move loads and constants to the right.
|
||||
static bool commute(Node *add, bool con_left, bool con_right) {
|
||||
static bool commute(PhaseGVN* phase, Node* add) {
|
||||
Node *in1 = add->in(1);
|
||||
Node *in2 = add->in(2);
|
||||
|
||||
// convert "max(a,b) + min(a,b)" into "a+b".
|
||||
if ((in1->Opcode() == add->as_Add()->max_opcode() && in2->Opcode() == add->as_Add()->min_opcode())
|
||||
|| (in1->Opcode() == add->as_Add()->min_opcode() && in2->Opcode() == add->as_Add()->max_opcode())) {
|
||||
Node *in11 = in1->in(1);
|
||||
Node *in12 = in1->in(2);
|
||||
|
||||
Node *in21 = in2->in(1);
|
||||
Node *in22 = in2->in(2);
|
||||
|
||||
if ((in11 == in21 && in12 == in22) ||
|
||||
(in11 == in22 && in12 == in21)) {
|
||||
add->set_req(1, in11);
|
||||
add->set_req(2, in12);
|
||||
PhaseIterGVN* igvn = phase->is_IterGVN();
|
||||
if (igvn) {
|
||||
igvn->_worklist.push(in1);
|
||||
igvn->_worklist.push(in2);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool con_left = phase->type(in1)->singleton();
|
||||
bool con_right = phase->type(in2)->singleton();
|
||||
|
||||
// Convert "1+x" into "x+1".
|
||||
// Right is a constant; leave it
|
||||
if( con_right ) return false;
|
||||
@ -115,7 +140,7 @@ Node *AddNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||
bool con_right = t2->singleton();
|
||||
|
||||
// Check for commutative operation desired
|
||||
if (commute(this, con_left, con_right)) return this;
|
||||
if (commute(phase, this)) return this;
|
||||
|
||||
AddNode *progress = NULL; // Progress flag
|
||||
|
||||
@ -539,9 +564,7 @@ Node *AddFNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||
}
|
||||
|
||||
// Floating point additions are not associative because of boundary conditions (infinity)
|
||||
return commute(this,
|
||||
phase->type( in(1) )->singleton(),
|
||||
phase->type( in(2) )->singleton() ) ? this : NULL;
|
||||
return commute(phase, this) ? this : NULL;
|
||||
}
|
||||
|
||||
|
||||
@ -576,9 +599,7 @@ Node *AddDNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||
}
|
||||
|
||||
// Floating point additions are not associative because of boundary conditions (infinity)
|
||||
return commute(this,
|
||||
phase->type( in(1) )->singleton(),
|
||||
phase->type( in(2) )->singleton() ) ? this : NULL;
|
||||
return commute(phase, this) ? this : NULL;
|
||||
}
|
||||
|
||||
|
||||
|
@ -68,6 +68,12 @@ public:
|
||||
// Supplied function to return the additive identity type
|
||||
virtual const Type *add_id() const = 0;
|
||||
|
||||
// Supplied function to return the additive opcode
|
||||
virtual int max_opcode() const = 0;
|
||||
|
||||
// Supplied function to return the multiplicative opcode
|
||||
virtual int min_opcode() const = 0;
|
||||
|
||||
virtual bool operates_on(BasicType bt, bool signed_int) const {
|
||||
assert(bt == T_INT || bt == T_LONG, "unsupported");
|
||||
return false;
|
||||
@ -84,6 +90,8 @@ public:
|
||||
virtual const Type *add_ring( const Type *, const Type * ) const;
|
||||
virtual const Type *add_id() const { return TypeInt::ZERO; }
|
||||
virtual const Type *bottom_type() const { return TypeInt::INT; }
|
||||
int max_opcode() const { return Op_MaxI; }
|
||||
int min_opcode() const { return Op_MinI; }
|
||||
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
|
||||
virtual Node* Identity(PhaseGVN* phase);
|
||||
virtual bool operates_on(BasicType bt, bool signed_int) const {
|
||||
@ -102,6 +110,8 @@ public:
|
||||
virtual const Type *add_ring( const Type *, const Type * ) const;
|
||||
virtual const Type *add_id() const { return TypeLong::ZERO; }
|
||||
virtual const Type *bottom_type() const { return TypeLong::LONG; }
|
||||
int max_opcode() const { return Op_MaxL; }
|
||||
int min_opcode() const { return Op_MinL; }
|
||||
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
|
||||
virtual Node* Identity(PhaseGVN* phase);
|
||||
virtual bool operates_on(BasicType bt, bool signed_int) const {
|
||||
@ -122,6 +132,8 @@ public:
|
||||
virtual const Type *add_ring( const Type *, const Type * ) const;
|
||||
virtual const Type *add_id() const { return TypeF::ZERO; }
|
||||
virtual const Type *bottom_type() const { return Type::FLOAT; }
|
||||
int max_opcode() const { return Op_MaxF; }
|
||||
int min_opcode() const { return Op_MinF; }
|
||||
virtual Node* Identity(PhaseGVN* phase) { return this; }
|
||||
virtual uint ideal_reg() const { return Op_RegF; }
|
||||
};
|
||||
@ -137,6 +149,8 @@ public:
|
||||
virtual const Type *add_ring( const Type *, const Type * ) const;
|
||||
virtual const Type *add_id() const { return TypeD::ZERO; }
|
||||
virtual const Type *bottom_type() const { return Type::DOUBLE; }
|
||||
int max_opcode() const { return Op_MaxD; }
|
||||
int min_opcode() const { return Op_MinD; }
|
||||
virtual Node* Identity(PhaseGVN* phase) { return this; }
|
||||
virtual uint ideal_reg() const { return Op_RegD; }
|
||||
};
|
||||
@ -183,6 +197,8 @@ public:
|
||||
virtual const Type *add_ring( const Type *, const Type * ) const;
|
||||
virtual const Type *add_id() const { return TypeInt::ZERO; }
|
||||
virtual const Type *bottom_type() const { return TypeInt::INT; }
|
||||
int max_opcode() const { return Op_MaxI; }
|
||||
int min_opcode() const { return Op_MinI; }
|
||||
virtual Node* Identity(PhaseGVN* phase);
|
||||
virtual uint ideal_reg() const { return Op_RegI; }
|
||||
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
|
||||
@ -198,6 +214,8 @@ public:
|
||||
virtual const Type *add_ring( const Type *, const Type * ) const;
|
||||
virtual const Type *add_id() const { return TypeLong::ZERO; }
|
||||
virtual const Type *bottom_type() const { return TypeLong::LONG; }
|
||||
int max_opcode() const { return Op_MaxL; }
|
||||
int min_opcode() const { return Op_MinL; }
|
||||
virtual Node* Identity(PhaseGVN* phase);
|
||||
virtual uint ideal_reg() const { return Op_RegL; }
|
||||
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
|
||||
@ -212,6 +230,8 @@ public:
|
||||
virtual const Type *add_ring( const Type *, const Type * ) const;
|
||||
virtual const Type *add_id() const { return TypeInt::ZERO; }
|
||||
virtual const Type *bottom_type() const { return TypeInt::INT; }
|
||||
int max_opcode() const { return Op_MaxI; }
|
||||
int min_opcode() const { return Op_MinI; }
|
||||
virtual const Type *Value(PhaseGVN *phase) const;
|
||||
virtual uint ideal_reg() const { return Op_RegI; }
|
||||
};
|
||||
@ -225,6 +245,8 @@ public:
|
||||
virtual const Type *add_ring( const Type *, const Type * ) const;
|
||||
virtual const Type *add_id() const { return TypeLong::ZERO; }
|
||||
virtual const Type *bottom_type() const { return TypeLong::LONG; }
|
||||
int max_opcode() const { return Op_MaxL; }
|
||||
int min_opcode() const { return Op_MinL; }
|
||||
virtual const Type *Value(PhaseGVN *phase) const;
|
||||
virtual uint ideal_reg() const { return Op_RegL; }
|
||||
};
|
||||
@ -241,6 +263,8 @@ private:
|
||||
public:
|
||||
MaxNode( Node *in1, Node *in2 ) : AddNode(in1,in2) {}
|
||||
virtual int Opcode() const = 0;
|
||||
virtual int max_opcode() const = 0;
|
||||
virtual int min_opcode() const = 0;
|
||||
|
||||
static Node* unsigned_max(Node* a, Node* b, const Type* t, PhaseGVN& gvn) {
|
||||
return build_min_max(a, b, true, true, t, gvn);
|
||||
@ -280,6 +304,8 @@ public:
|
||||
virtual const Type *add_id() const { return TypeInt::make(min_jint); }
|
||||
virtual const Type *bottom_type() const { return TypeInt::INT; }
|
||||
virtual uint ideal_reg() const { return Op_RegI; }
|
||||
int max_opcode() const { return Op_MaxI; }
|
||||
int min_opcode() const { return Op_MinI; }
|
||||
};
|
||||
|
||||
//------------------------------MinINode---------------------------------------
|
||||
@ -293,6 +319,8 @@ public:
|
||||
virtual const Type *add_id() const { return TypeInt::make(max_jint); }
|
||||
virtual const Type *bottom_type() const { return TypeInt::INT; }
|
||||
virtual uint ideal_reg() const { return Op_RegI; }
|
||||
int max_opcode() const { return Op_MaxI; }
|
||||
int min_opcode() const { return Op_MinI; }
|
||||
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
|
||||
};
|
||||
|
||||
@ -306,6 +334,8 @@ public:
|
||||
virtual const Type *add_id() const { return TypeLong::make(min_jlong); }
|
||||
virtual const Type *bottom_type() const { return TypeLong::LONG; }
|
||||
virtual uint ideal_reg() const { return Op_RegL; }
|
||||
int max_opcode() const { return Op_MaxL; }
|
||||
int min_opcode() const { return Op_MinL; }
|
||||
};
|
||||
|
||||
//------------------------------MinLNode---------------------------------------
|
||||
@ -318,6 +348,8 @@ public:
|
||||
virtual const Type *add_id() const { return TypeLong::make(max_jlong); }
|
||||
virtual const Type *bottom_type() const { return TypeLong::LONG; }
|
||||
virtual uint ideal_reg() const { return Op_RegL; }
|
||||
int max_opcode() const { return Op_MaxL; }
|
||||
int min_opcode() const { return Op_MinL; }
|
||||
};
|
||||
|
||||
//------------------------------MaxFNode---------------------------------------
|
||||
@ -330,6 +362,8 @@ public:
|
||||
virtual const Type *add_id() const { return TypeF::NEG_INF; }
|
||||
virtual const Type *bottom_type() const { return Type::FLOAT; }
|
||||
virtual uint ideal_reg() const { return Op_RegF; }
|
||||
int max_opcode() const { return Op_MaxF; }
|
||||
int min_opcode() const { return Op_MinF; }
|
||||
};
|
||||
|
||||
//------------------------------MinFNode---------------------------------------
|
||||
@ -342,6 +376,8 @@ public:
|
||||
virtual const Type *add_id() const { return TypeF::POS_INF; }
|
||||
virtual const Type *bottom_type() const { return Type::FLOAT; }
|
||||
virtual uint ideal_reg() const { return Op_RegF; }
|
||||
int max_opcode() const { return Op_MaxF; }
|
||||
int min_opcode() const { return Op_MinF; }
|
||||
};
|
||||
|
||||
//------------------------------MaxDNode---------------------------------------
|
||||
@ -354,6 +390,8 @@ public:
|
||||
virtual const Type *add_id() const { return TypeD::NEG_INF; }
|
||||
virtual const Type *bottom_type() const { return Type::DOUBLE; }
|
||||
virtual uint ideal_reg() const { return Op_RegD; }
|
||||
int max_opcode() const { return Op_MaxD; }
|
||||
int min_opcode() const { return Op_MinD; }
|
||||
};
|
||||
|
||||
//------------------------------MinDNode---------------------------------------
|
||||
@ -366,6 +404,8 @@ public:
|
||||
virtual const Type *add_id() const { return TypeD::POS_INF; }
|
||||
virtual const Type *bottom_type() const { return Type::DOUBLE; }
|
||||
virtual uint ideal_reg() const { return Op_RegD; }
|
||||
int max_opcode() const { return Op_MaxD; }
|
||||
int min_opcode() const { return Op_MinD; }
|
||||
};
|
||||
|
||||
#endif // SHARE_OPTO_ADDNODE_HPP
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2021, 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
|
||||
@ -62,6 +62,31 @@ Node *MulNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||
const Type *t1 = phase->type( in(1) );
|
||||
const Type *t2 = phase->type( in(2) );
|
||||
Node *progress = NULL; // Progress flag
|
||||
|
||||
// convert "max(a,b) * min(a,b)" into "a*b".
|
||||
Node *in1 = in(1);
|
||||
Node *in2 = in(2);
|
||||
if ((in(1)->Opcode() == max_opcode() && in(2)->Opcode() == min_opcode())
|
||||
|| (in(1)->Opcode() == min_opcode() && in(2)->Opcode() == max_opcode())) {
|
||||
Node *in11 = in(1)->in(1);
|
||||
Node *in12 = in(1)->in(2);
|
||||
|
||||
Node *in21 = in(2)->in(1);
|
||||
Node *in22 = in(2)->in(2);
|
||||
|
||||
if ((in11 == in21 && in12 == in22) ||
|
||||
(in11 == in22 && in12 == in21)) {
|
||||
set_req(1, in11);
|
||||
set_req(2, in12);
|
||||
PhaseIterGVN* igvn = phase->is_IterGVN();
|
||||
if (igvn) {
|
||||
igvn->_worklist.push(in1);
|
||||
igvn->_worklist.push(in2);
|
||||
}
|
||||
progress = this;
|
||||
}
|
||||
}
|
||||
|
||||
// We are OK if right is a constant, or right is a load and
|
||||
// left is a non-constant.
|
||||
if( !(t2->singleton() ||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2021, 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
|
||||
@ -75,6 +75,11 @@ public:
|
||||
// Supplied function to return the multiplicative opcode
|
||||
virtual int mul_opcode() const = 0;
|
||||
|
||||
// Supplied function to return the additive opcode
|
||||
virtual int max_opcode() const = 0;
|
||||
|
||||
// Supplied function to return the multiplicative opcode
|
||||
virtual int min_opcode() const = 0;
|
||||
};
|
||||
|
||||
//------------------------------MulINode---------------------------------------
|
||||
@ -89,6 +94,8 @@ public:
|
||||
const Type *add_id() const { return TypeInt::ZERO; }
|
||||
int add_opcode() const { return Op_AddI; }
|
||||
int mul_opcode() const { return Op_MulI; }
|
||||
int max_opcode() const { return Op_MaxI; }
|
||||
int min_opcode() const { return Op_MinI; }
|
||||
const Type *bottom_type() const { return TypeInt::INT; }
|
||||
virtual uint ideal_reg() const { return Op_RegI; }
|
||||
};
|
||||
@ -105,6 +112,8 @@ public:
|
||||
const Type *add_id() const { return TypeLong::ZERO; }
|
||||
int add_opcode() const { return Op_AddL; }
|
||||
int mul_opcode() const { return Op_MulL; }
|
||||
int max_opcode() const { return Op_MaxL; }
|
||||
int min_opcode() const { return Op_MinL; }
|
||||
const Type *bottom_type() const { return TypeLong::LONG; }
|
||||
virtual uint ideal_reg() const { return Op_RegL; }
|
||||
};
|
||||
@ -121,6 +130,8 @@ public:
|
||||
const Type *add_id() const { return TypeF::ZERO; }
|
||||
int add_opcode() const { return Op_AddF; }
|
||||
int mul_opcode() const { return Op_MulF; }
|
||||
int max_opcode() const { return Op_MaxF; }
|
||||
int min_opcode() const { return Op_MinF; }
|
||||
const Type *bottom_type() const { return Type::FLOAT; }
|
||||
virtual uint ideal_reg() const { return Op_RegF; }
|
||||
};
|
||||
@ -136,6 +147,8 @@ public:
|
||||
const Type *add_id() const { return TypeD::ZERO; }
|
||||
int add_opcode() const { return Op_AddD; }
|
||||
int mul_opcode() const { return Op_MulD; }
|
||||
int max_opcode() const { return Op_MaxD; }
|
||||
int min_opcode() const { return Op_MinD; }
|
||||
const Type *bottom_type() const { return Type::DOUBLE; }
|
||||
virtual uint ideal_reg() const { return Op_RegD; }
|
||||
};
|
||||
@ -165,6 +178,8 @@ public:
|
||||
const Type *add_id() const { return TypeInt::ZERO; }
|
||||
int add_opcode() const { return Op_OrI; }
|
||||
int mul_opcode() const { return Op_AndI; }
|
||||
int max_opcode() const { return Op_MaxI; }
|
||||
int min_opcode() const { return Op_MinI; }
|
||||
virtual uint ideal_reg() const { return Op_RegI; }
|
||||
};
|
||||
|
||||
@ -182,6 +197,8 @@ public:
|
||||
const Type *add_id() const { return TypeLong::ZERO; }
|
||||
int add_opcode() const { return Op_OrL; }
|
||||
int mul_opcode() const { return Op_AndL; }
|
||||
int max_opcode() const { return Op_MaxL; }
|
||||
int min_opcode() const { return Op_MinL; }
|
||||
virtual uint ideal_reg() const { return Op_RegL; }
|
||||
};
|
||||
|
||||
|
@ -0,0 +1,209 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Huawei Technologies Co. Ltd. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8263006
|
||||
* @summary Test the result of 8263006's optimization
|
||||
*
|
||||
* @run main/othervm -Xcomp -XX:-TieredCompilation
|
||||
* compiler.intrinsics.math.MaxMinOptimizeTest
|
||||
*/
|
||||
|
||||
package compiler.intrinsics.math;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class MaxMinOptimizeTest {
|
||||
|
||||
private static final float fPos = 15280.0f;
|
||||
private static final float fNeg = -55555.5f;
|
||||
private static final float fPosZero = 0.0f;
|
||||
private static final float fNegZero = -0.0f;
|
||||
private static final float fPosInf = Float.POSITIVE_INFINITY;
|
||||
private static final float fNegInf = Float.NEGATIVE_INFINITY;
|
||||
private static final float fNaN = Float.NaN;
|
||||
|
||||
private static final float fPosPosAdd = Float.intBitsToFloat(1190051840);
|
||||
private static final float fNegNegAdd = Float.intBitsToFloat(-942079104);
|
||||
private static final float fPosNegAdd = Float.intBitsToFloat(-954379392);
|
||||
private static final float fPosPosMul = Float.intBitsToFloat(1298049424);
|
||||
private static final float fNegNegMul = Float.intBitsToFloat(1329067759);
|
||||
private static final float fPosNegMul = Float.intBitsToFloat(-833985532);
|
||||
|
||||
private static final double dPos = 482390926662501720.0;
|
||||
private static final double dNeg = -333333333333333333.3;
|
||||
private static final double dPosZero = 0.0;
|
||||
private static final double dNegZero = -0.0;
|
||||
private static final double dPosInf = Double.POSITIVE_INFINITY;
|
||||
private static final double dNegInf = Double.NEGATIVE_INFINITY;
|
||||
private static final double dNaN = Double.NaN;
|
||||
|
||||
private static final double dPosPosAdd = Double.longBitsToDouble(4875928555416607765L);
|
||||
private static final double dNegNegAdd = Double.longBitsToDouble(-4349772506333936299L);
|
||||
private static final double dPosNegAdd = Double.longBitsToDouble(4864042047724301696L);
|
||||
private static final double dPosPosMul = Double.longBitsToDouble(5135907348984537565L);
|
||||
private static final double dNegNegMul = Double.longBitsToDouble(5131119721350321694L);
|
||||
private static final double dPosNegMul = Double.longBitsToDouble(-4089558839395905027L);
|
||||
|
||||
private static final float[][] f_cases = {
|
||||
// a b min max add mul
|
||||
{ fPos, fPos, fPos, fPos, fPosPosAdd, fPosPosMul},
|
||||
{ fNeg, fNeg, fNeg, fNeg, fNegNegAdd, fNegNegMul},
|
||||
{ fPos, fNeg, fNeg, fPos, fPosNegAdd, fPosNegMul},
|
||||
{ fNeg, fPos, fNeg, fPos, fPosNegAdd, fPosNegMul},
|
||||
|
||||
{ fPosZero, fNegZero, fNegZero, fPosZero, fPosZero, fNegZero},
|
||||
{ fNegZero, fPosZero, fNegZero, fPosZero, fPosZero, fNegZero},
|
||||
{ fNegZero, fNegZero, fNegZero, fNegZero, fNegZero, fPosZero},
|
||||
|
||||
{ fPos, fPosInf, fPos, fPosInf, fPosInf, fPosInf},
|
||||
{ fNeg, fNegInf, fNegInf, fNeg, fNegInf, fPosInf},
|
||||
|
||||
{ fPos, fNaN, fNaN, fNaN, fNaN, fNaN},
|
||||
{ fNaN, fPos, fNaN, fNaN, fNaN, fNaN},
|
||||
{ fNeg, fNaN, fNaN, fNaN, fNaN, fNaN},
|
||||
{ fNaN, fNeg, fNaN, fNaN, fNaN, fNaN},
|
||||
|
||||
{ fPosInf, fNaN, fNaN, fNaN, fNaN, fNaN},
|
||||
{ fNaN, fPosInf, fNaN, fNaN, fNaN, fNaN},
|
||||
{ fNegInf, fNaN, fNaN, fNaN, fNaN, fNaN},
|
||||
{ fNaN, fNegInf, fNaN, fNaN, fNaN, fNaN}
|
||||
};
|
||||
|
||||
private static final double[][] d_cases = {
|
||||
// a b min max add mul
|
||||
{ dPos, dPos, dPos, dPos, dPosPosAdd, dPosPosMul},
|
||||
{ dNeg, dNeg, dNeg, dNeg, dNegNegAdd, dNegNegMul},
|
||||
{ dPos, dNeg, dNeg, dPos, dPosNegAdd, dPosNegMul},
|
||||
{ dNeg, dPos, dNeg, dPos, dPosNegAdd, dPosNegMul},
|
||||
|
||||
{ dPosZero, dNegZero, dNegZero, dPosZero, dPosZero, dNegZero},
|
||||
{ dNegZero, dPosZero, dNegZero, dPosZero, dPosZero, dNegZero},
|
||||
{ dNegZero, dNegZero, dNegZero, dNegZero, dNegZero, dPosZero},
|
||||
|
||||
{ dPos, dPosInf, dPos, dPosInf, dPosInf, dPosInf},
|
||||
{ dNeg, dNegInf, dNegInf, dNeg, dNegInf, dPosInf},
|
||||
|
||||
{ dPos, dNaN, dNaN, dNaN, dNaN, dNaN},
|
||||
{ dNaN, dPos, dNaN, dNaN, dNaN, dNaN},
|
||||
{ dNeg, dNaN, dNaN, dNaN, dNaN, dNaN},
|
||||
{ dNaN, dNeg, dNaN, dNaN, dNaN, dNaN},
|
||||
|
||||
{ dPosInf, dNaN, dNaN, dNaN, dNaN, dNaN},
|
||||
{ dNaN, dPosInf, dNaN, dNaN, dNaN, dNaN},
|
||||
{ dNegInf, dNaN, dNaN, dNaN, dNaN, dNaN},
|
||||
{ dNaN, dNegInf, dNaN, dNaN, dNaN, dNaN}
|
||||
};
|
||||
|
||||
static float add_opt_float(float a, float b) {
|
||||
return Math.max(a, b) + Math.min(a, b);
|
||||
}
|
||||
|
||||
static float mul_opt_float(float a, float b) {
|
||||
return Math.max(a, b) * Math.min(a, b);
|
||||
}
|
||||
|
||||
static float max_opt_float(float a, float b) {
|
||||
return Math.max(Math.max(a, b), Math.min(a, b));
|
||||
}
|
||||
|
||||
static float min_opt_float(float a, float b) {
|
||||
return Math.min(Math.max(a, b), Math.min(a, b));
|
||||
}
|
||||
|
||||
static double add_opt_double(double a, double b) {
|
||||
return Math.max(a, b) + Math.min(a, b);
|
||||
}
|
||||
|
||||
static double mul_opt_double(double a, double b) {
|
||||
return Math.max(a, b) * Math.min(a, b);
|
||||
}
|
||||
|
||||
static double max_opt_double(double a, double b) {
|
||||
return Math.max(Math.max(a, b), Math.min(a, b));
|
||||
}
|
||||
|
||||
static double min_opt_double(double a, double b) {
|
||||
return Math.min(Math.max(a, b), Math.min(a, b));
|
||||
}
|
||||
|
||||
private static void fTest(float[] row) {
|
||||
fCheck(row[0], row[1],
|
||||
min_opt_float(row[0], row[1]),
|
||||
max_opt_float(row[0], row[1]),
|
||||
add_opt_float(row[0], row[1]),
|
||||
mul_opt_float(row[0], row[1]),
|
||||
row[2], row[3], row[4], row[5]);
|
||||
}
|
||||
|
||||
private static void fCheck(float a, float b, float fmin, float fmax, float fadd, float fmul, float efmin, float efmax, float efadd, float efmul) {
|
||||
int min = Float.floatToRawIntBits(fmin);
|
||||
int max = Float.floatToRawIntBits(fmax);
|
||||
int add = Float.floatToRawIntBits(fadd);
|
||||
int mul = Float.floatToRawIntBits(fmul);
|
||||
int emin = Float.floatToRawIntBits(efmin);
|
||||
int emax = Float.floatToRawIntBits(efmax);
|
||||
int eadd = Float.floatToRawIntBits(efadd);
|
||||
int emul = Float.floatToRawIntBits(efmul);
|
||||
|
||||
if (min != emin || max != emax || add != eadd || mul != emul) {
|
||||
throw new AssertionError("Unexpected result of float test: " +
|
||||
"a = " + a + ", b = " + b + ", " +
|
||||
"result = (" + fmin + ", " + fmax + ", " + fadd + ", " + fmul + "), " +
|
||||
"expected = (" + efmin + ", " + efmax + ", " + efadd + ", " + efmul + ")");
|
||||
}
|
||||
}
|
||||
|
||||
private static void dTest(double[] row) {
|
||||
dCheck(row[0], row[1],
|
||||
min_opt_double(row[0], row[1]),
|
||||
max_opt_double(row[0], row[1]),
|
||||
add_opt_double(row[0], row[1]),
|
||||
mul_opt_double(row[0], row[1]),
|
||||
row[2], row[3], row[4], row[5]);
|
||||
}
|
||||
|
||||
private static void dCheck(double a, double b, double dmin, double dmax, double dadd, double dmul, double edmin, double edmax, double edadd, double edmul) {
|
||||
long min = Double.doubleToRawLongBits(dmin);
|
||||
long max = Double.doubleToRawLongBits(dmax);
|
||||
long add = Double.doubleToRawLongBits(dadd);
|
||||
long mul = Double.doubleToRawLongBits(dmul);
|
||||
long emin = Double.doubleToRawLongBits(edmin);
|
||||
long emax = Double.doubleToRawLongBits(edmax);
|
||||
long eadd = Double.doubleToRawLongBits(edadd);
|
||||
long emul = Double.doubleToRawLongBits(edmul);
|
||||
|
||||
if (min != emin || max != emax || add != eadd || mul != emul) {
|
||||
throw new AssertionError("Unexpected result of double test: " +
|
||||
"a = " + a + ", b = " + b + ", " +
|
||||
"result = (" + dmin + ", " + dmax + ", " + dadd + ", " + dmul + "), " +
|
||||
"expected = (" + edmin + ", " + edmax + ", " + edadd + ", " + edmul + ")");
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
Arrays.stream(f_cases).forEach(MaxMinOptimizeTest::fTest);
|
||||
Arrays.stream(d_cases).forEach(MaxMinOptimizeTest::dTest);
|
||||
}
|
||||
}
|
151
test/micro/org/openjdk/bench/vm/compiler/MaxMinOptimizeTest.java
Normal file
151
test/micro/org/openjdk/bench/vm/compiler/MaxMinOptimizeTest.java
Normal file
@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Huawei Technologies Co. Ltd. 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.Benchmark;
|
||||
import org.openjdk.jmh.annotations.*;
|
||||
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.openjdk.jmh.infra.Blackhole;
|
||||
|
||||
@BenchmarkMode({Mode.AverageTime})
|
||||
@OutputTimeUnit(TimeUnit.MICROSECONDS)
|
||||
@State(Scope.Thread)
|
||||
public class MaxMinOptimizeTest {
|
||||
private static final int COUNT = 100000;
|
||||
|
||||
private float[] floats_a = new float[COUNT];
|
||||
private float[] floats_b = new float[COUNT];
|
||||
private double[] doubles_a = new double[COUNT];
|
||||
private double[] doubles_b = new double[COUNT];
|
||||
|
||||
private Random r = new Random();
|
||||
|
||||
@Setup
|
||||
public void init() {
|
||||
for (int i=0; i<COUNT; i++) {
|
||||
floats_a[i] = r.nextFloat();
|
||||
floats_b[i] = r.nextFloat();
|
||||
doubles_a[i] = r.nextDouble();
|
||||
doubles_b[i] = r.nextDouble();
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void fAdd(Blackhole bh) {
|
||||
float sum = 0;
|
||||
for (int i=0; i<COUNT; i++)
|
||||
sum += fAddBench(floats_a[i], floats_b[i]);
|
||||
bh.consume(sum);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void fMul(Blackhole bh) {
|
||||
float sum = 0;
|
||||
for (int i=0; i<COUNT; i++)
|
||||
sum += fMulBench(floats_a[i], floats_b[i]);
|
||||
bh.consume(sum);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void fMax(Blackhole bh) {
|
||||
float sum = 0;
|
||||
for (int i=0; i<COUNT; i++)
|
||||
sum += fMaxBench(floats_a[i], floats_b[i]);
|
||||
bh.consume(sum);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void fMin(Blackhole bh) {
|
||||
float sum = 0;
|
||||
for (int i=0; i<COUNT; i++)
|
||||
sum += fMinBench(floats_a[i], floats_b[i]);
|
||||
bh.consume(sum);
|
||||
}
|
||||
|
||||
private float fAddBench(float a, float b) {
|
||||
return Math.max(a, b) + Math.min(a, b);
|
||||
}
|
||||
|
||||
private float fMulBench(float a, float b) {
|
||||
return Math.max(a, b) * Math.min(a, b);
|
||||
}
|
||||
|
||||
private float fMaxBench(float a, float b) {
|
||||
return Math.max(Math.max(a, b), Math.min(a, b));
|
||||
}
|
||||
|
||||
private float fMinBench(float a, float b) {
|
||||
return Math.min(Math.max(a, b), Math.min(a, b));
|
||||
}
|
||||
|
||||
|
||||
@Benchmark
|
||||
public void dAdd(Blackhole bh) {
|
||||
double sum = 0;
|
||||
for (int i=0; i<COUNT; i++)
|
||||
sum += dAddBench(doubles_a[i], doubles_b[i]);
|
||||
bh.consume(sum);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void dMul(Blackhole bh) {
|
||||
double sum = 0;
|
||||
for (int i=0; i<COUNT; i++)
|
||||
sum += dMulBench(doubles_a[i], doubles_b[i]);
|
||||
bh.consume(sum);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void dMax(Blackhole bh) {
|
||||
double sum = 0;
|
||||
for (int i=0; i<COUNT; i++)
|
||||
sum += dMaxBench(doubles_a[i], doubles_b[i]);
|
||||
bh.consume(sum);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void dMin(Blackhole bh) {
|
||||
double sum = 0;
|
||||
for (int i=0; i<COUNT; i++)
|
||||
sum += dMinBench(doubles_a[i], doubles_b[i]);
|
||||
bh.consume(sum);
|
||||
}
|
||||
|
||||
private double dAddBench(double a, double b) {
|
||||
return Math.max(a, b) + Math.min(a, b);
|
||||
}
|
||||
|
||||
private double dMulBench(double a, double b) {
|
||||
return Math.max(a, b) * Math.min(a, b);
|
||||
}
|
||||
|
||||
private double dMaxBench(double a, double b) {
|
||||
return Math.max(Math.max(a, b), Math.min(a, b));
|
||||
}
|
||||
|
||||
private double dMinBench(double a, double b) {
|
||||
return Math.min(Math.max(a, b), Math.min(a, b));
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user