8226721: Missing intrinsics for Math.ceil, floor, rint
Reviewed-by: neliasso, vlivanov, ecaspole
This commit is contained in:
parent
09c012be4e
commit
d3ca3a02ff
@ -4742,6 +4742,25 @@ void Assembler::smovl() {
|
||||
emit_int8((unsigned char)0xA5);
|
||||
}
|
||||
|
||||
void Assembler::roundsd(XMMRegister dst, XMMRegister src, int32_t rmode) {
|
||||
assert(VM_Version::supports_sse4_1(), "");
|
||||
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false);
|
||||
int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes);
|
||||
emit_int8(0x0B);
|
||||
emit_int8((unsigned char)(0xC0 | encode));
|
||||
emit_int8((unsigned char)rmode);
|
||||
}
|
||||
|
||||
void Assembler::roundsd(XMMRegister dst, Address src, int32_t rmode) {
|
||||
assert(VM_Version::supports_sse4_1(), "");
|
||||
InstructionMark im(this);
|
||||
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false);
|
||||
simd_prefix(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes);
|
||||
emit_int8(0x0B);
|
||||
emit_operand(dst, src);
|
||||
emit_int8((unsigned char)rmode);
|
||||
}
|
||||
|
||||
void Assembler::sqrtsd(XMMRegister dst, XMMRegister src) {
|
||||
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
|
||||
InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
|
||||
@ -5539,6 +5558,49 @@ void Assembler::vdivps(XMMRegister dst, XMMRegister nds, Address src, int vector
|
||||
emit_operand(dst, src);
|
||||
}
|
||||
|
||||
void Assembler::vroundpd(XMMRegister dst, XMMRegister src, int32_t rmode, int vector_len) {
|
||||
assert(VM_Version::supports_avx(), "");
|
||||
InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false);
|
||||
int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes);
|
||||
emit_int8(0x09);
|
||||
emit_int8((unsigned char)(0xC0 | encode));
|
||||
emit_int8((unsigned char)(rmode));
|
||||
}
|
||||
|
||||
void Assembler::vroundpd(XMMRegister dst, Address src, int32_t rmode, int vector_len) {
|
||||
assert(VM_Version::supports_avx(), "");
|
||||
InstructionMark im(this);
|
||||
InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false);
|
||||
vex_prefix(src, 0, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes);
|
||||
emit_int8(0x09);
|
||||
emit_operand(dst, src);
|
||||
emit_int8((unsigned char)(rmode));
|
||||
}
|
||||
|
||||
void Assembler::vrndscalepd(XMMRegister dst, XMMRegister src, int32_t rmode, int vector_len) {
|
||||
assert(VM_Version::supports_evex(), "requires EVEX support");
|
||||
InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
|
||||
attributes.set_is_evex_instruction();
|
||||
int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes);
|
||||
emit_int8((unsigned char)0x09);
|
||||
emit_int8((unsigned char)(0xC0 | encode));
|
||||
emit_int8((unsigned char)(rmode));
|
||||
}
|
||||
|
||||
void Assembler::vrndscalepd(XMMRegister dst, Address src, int32_t rmode, int vector_len) {
|
||||
assert(VM_Version::supports_evex(), "requires EVEX support");
|
||||
assert(dst != xnoreg, "sanity");
|
||||
InstructionMark im(this);
|
||||
InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
|
||||
attributes.set_is_evex_instruction();
|
||||
attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit);
|
||||
vex_prefix(src, 0, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes);
|
||||
emit_int8((unsigned char)0x09);
|
||||
emit_operand(dst, src);
|
||||
emit_int8((unsigned char)(rmode));
|
||||
}
|
||||
|
||||
|
||||
void Assembler::vsqrtpd(XMMRegister dst, XMMRegister src, int vector_len) {
|
||||
assert(VM_Version::supports_avx(), "");
|
||||
InstructionAttr attributes(vector_len, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
|
||||
|
@ -1856,6 +1856,9 @@ private:
|
||||
void sqrtsd(XMMRegister dst, Address src);
|
||||
void sqrtsd(XMMRegister dst, XMMRegister src);
|
||||
|
||||
void roundsd(XMMRegister dst, Address src, int32_t rmode);
|
||||
void roundsd(XMMRegister dst, XMMRegister src, int32_t rmode);
|
||||
|
||||
// Compute Square Root of Scalar Single-Precision Floating-Point Value
|
||||
void sqrtss(XMMRegister dst, Address src);
|
||||
void sqrtss(XMMRegister dst, XMMRegister src);
|
||||
@ -2020,6 +2023,12 @@ private:
|
||||
void vsqrtps(XMMRegister dst, XMMRegister src, int vector_len);
|
||||
void vsqrtps(XMMRegister dst, Address src, int vector_len);
|
||||
|
||||
// Round Packed Double precision value.
|
||||
void vroundpd(XMMRegister dst, XMMRegister src, int32_t rmode, int vector_len);
|
||||
void vroundpd(XMMRegister dst, Address src, int32_t rmode, int vector_len);
|
||||
void vrndscalepd(XMMRegister dst, XMMRegister src, int32_t rmode, int vector_len);
|
||||
void vrndscalepd(XMMRegister dst, Address src, int32_t rmode, int vector_len);
|
||||
|
||||
// Bitwise Logical AND of Packed Floating-Point Values
|
||||
void andpd(XMMRegister dst, XMMRegister src);
|
||||
void andps(XMMRegister dst, XMMRegister src);
|
||||
|
@ -3661,6 +3661,15 @@ void MacroAssembler::subsd(XMMRegister dst, AddressLiteral src) {
|
||||
}
|
||||
}
|
||||
|
||||
void MacroAssembler::roundsd(XMMRegister dst, AddressLiteral src, int32_t rmode, Register scratch_reg) {
|
||||
if (reachable(src)) {
|
||||
Assembler::roundsd(dst, as_Address(src), rmode);
|
||||
} else {
|
||||
lea(scratch_reg, src);
|
||||
Assembler::roundsd(dst, Address(scratch_reg, 0), rmode);
|
||||
}
|
||||
}
|
||||
|
||||
void MacroAssembler::subss(XMMRegister dst, AddressLiteral src) {
|
||||
if (reachable(src)) {
|
||||
Assembler::subss(dst, as_Address(src));
|
||||
|
@ -1180,6 +1180,10 @@ public:
|
||||
void sqrtsd(XMMRegister dst, Address src) { Assembler::sqrtsd(dst, src); }
|
||||
void sqrtsd(XMMRegister dst, AddressLiteral src);
|
||||
|
||||
void roundsd(XMMRegister dst, XMMRegister src, int32_t rmode) { Assembler::roundsd(dst, src, rmode); }
|
||||
void roundsd(XMMRegister dst, Address src, int32_t rmode) { Assembler::roundsd(dst, src, rmode); }
|
||||
void roundsd(XMMRegister dst, AddressLiteral src, int32_t rmode, Register scratch_reg);
|
||||
|
||||
void sqrtss(XMMRegister dst, XMMRegister src) { Assembler::sqrtss(dst, src); }
|
||||
void sqrtss(XMMRegister dst, Address src) { Assembler::sqrtss(dst, src); }
|
||||
void sqrtss(XMMRegister dst, AddressLiteral src);
|
||||
|
@ -1485,6 +1485,10 @@ const bool Matcher::match_rule_supported(int opcode) {
|
||||
ret_value = false;
|
||||
}
|
||||
break;
|
||||
case Op_RoundDoubleMode:
|
||||
if (UseSSE < 4)
|
||||
ret_value = false;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret_value; // Per default match rules are supported.
|
||||
@ -1536,6 +1540,10 @@ const bool Matcher::match_rule_supported_vector(int opcode, int vlen) {
|
||||
if (vlen != 4)
|
||||
ret_value = false;
|
||||
break;
|
||||
case Op_RoundDoubleModeV:
|
||||
if (VM_Version::supports_avx() == false)
|
||||
ret_value = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2854,6 +2862,108 @@ instruct sqrtD_imm(regD dst, immD con) %{
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
|
||||
instruct roundD_reg(legRegD dst, legRegD src, immU8 rmode) %{
|
||||
predicate(UseSSE>=4);
|
||||
match(Set dst (RoundDoubleMode src rmode));
|
||||
format %{ "roundsd $dst, $src" %}
|
||||
ins_cost(150);
|
||||
ins_encode %{
|
||||
__ roundsd($dst$$XMMRegister, $src$$XMMRegister, $rmode$$constant);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct roundD_mem(legRegD dst, memory src, immU8 rmode) %{
|
||||
predicate(UseSSE>=4);
|
||||
match(Set dst (RoundDoubleMode (LoadD src) rmode));
|
||||
format %{ "roundsd $dst, $src" %}
|
||||
ins_cost(150);
|
||||
ins_encode %{
|
||||
__ roundsd($dst$$XMMRegister, $src$$Address, $rmode$$constant);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct roundD_imm(legRegD dst, immD con, immU8 rmode, rRegI scratch_reg) %{
|
||||
predicate(UseSSE>=4);
|
||||
match(Set dst (RoundDoubleMode con rmode));
|
||||
effect(TEMP scratch_reg);
|
||||
format %{ "roundsd $dst, [$constantaddress]\t# load from constant table: double=$con" %}
|
||||
ins_cost(150);
|
||||
ins_encode %{
|
||||
__ roundsd($dst$$XMMRegister, $constantaddress($con), $rmode$$constant, $scratch_reg$$Register);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct vround2D_reg(legVecX dst, legVecX src, immU8 rmode) %{
|
||||
predicate(UseAVX > 0 && n->as_Vector()->length() == 2);
|
||||
match(Set dst (RoundDoubleModeV src rmode));
|
||||
format %{ "vroundpd $dst, $src, $rmode\t! round packed2D" %}
|
||||
ins_encode %{
|
||||
int vector_len = 0;
|
||||
__ vroundpd($dst$$XMMRegister, $src$$XMMRegister, $rmode$$constant, vector_len);
|
||||
%}
|
||||
ins_pipe( pipe_slow );
|
||||
%}
|
||||
|
||||
instruct vround2D_mem(legVecX dst, memory mem, immU8 rmode) %{
|
||||
predicate(UseAVX > 0 && n->as_Vector()->length() == 2);
|
||||
match(Set dst (RoundDoubleModeV (LoadVector mem) rmode));
|
||||
format %{ "vroundpd $dst, $mem, $rmode\t! round packed2D" %}
|
||||
ins_encode %{
|
||||
int vector_len = 0;
|
||||
__ vroundpd($dst$$XMMRegister, $mem$$Address, $rmode$$constant, vector_len);
|
||||
%}
|
||||
ins_pipe( pipe_slow );
|
||||
%}
|
||||
|
||||
instruct vround4D_reg(legVecY dst, legVecY src, legVecY rmode) %{
|
||||
predicate(UseAVX > 0 && n->as_Vector()->length() == 4);
|
||||
match(Set dst (RoundDoubleModeV src rmode));
|
||||
format %{ "vroundpd $dst, $src, $rmode\t! round packed4D" %}
|
||||
ins_encode %{
|
||||
int vector_len = 1;
|
||||
__ vroundpd($dst$$XMMRegister, $src$$XMMRegister, $rmode$$constant, vector_len);
|
||||
%}
|
||||
ins_pipe( pipe_slow );
|
||||
%}
|
||||
|
||||
instruct vround4D_mem(legVecY dst, memory mem, immU8 rmode) %{
|
||||
predicate(UseAVX > 0 && n->as_Vector()->length() == 4);
|
||||
match(Set dst (RoundDoubleModeV (LoadVector mem) rmode));
|
||||
format %{ "vroundpd $dst, $mem, $rmode\t! round packed4D" %}
|
||||
ins_encode %{
|
||||
int vector_len = 1;
|
||||
__ vroundpd($dst$$XMMRegister, $mem$$Address, $rmode$$constant, vector_len);
|
||||
%}
|
||||
ins_pipe( pipe_slow );
|
||||
%}
|
||||
|
||||
|
||||
instruct vround8D_reg(vecZ dst, vecZ src, immU8 rmode) %{
|
||||
predicate(UseAVX > 2 && n->as_Vector()->length() == 8);
|
||||
match(Set dst (RoundDoubleModeV src rmode));
|
||||
format %{ "vrndscalepd $dst, $src, $rmode\t! round packed8D" %}
|
||||
ins_encode %{
|
||||
int vector_len = 2;
|
||||
__ vrndscalepd($dst$$XMMRegister, $src$$XMMRegister, $rmode$$constant, vector_len);
|
||||
%}
|
||||
ins_pipe( pipe_slow );
|
||||
%}
|
||||
|
||||
instruct vround8D_mem(vecZ dst, memory mem, immU8 rmode) %{
|
||||
predicate(UseAVX > 2 && n->as_Vector()->length() == 8);
|
||||
match(Set dst (RoundDoubleModeV (LoadVector mem) rmode));
|
||||
format %{ "vrndscalepd $dst, $mem, $rmode\t! round packed8D" %}
|
||||
ins_encode %{
|
||||
int vector_len = 2;
|
||||
__ vrndscalepd($dst$$XMMRegister, $mem$$Address, $rmode$$constant, vector_len);
|
||||
%}
|
||||
ins_pipe( pipe_slow );
|
||||
%}
|
||||
|
||||
instruct onspinwait() %{
|
||||
match(OnSpinWait);
|
||||
ins_cost(200);
|
||||
|
@ -4047,6 +4047,7 @@ int MatchRule::is_expensive() const {
|
||||
strcmp(opType,"FmaD") == 0 ||
|
||||
strcmp(opType,"FmaF") == 0 ||
|
||||
strcmp(opType,"RoundDouble")==0 ||
|
||||
strcmp(opType,"RoundDoubleMode")==0 ||
|
||||
strcmp(opType,"RoundFloat")==0 ||
|
||||
strcmp(opType,"ReverseBytesI")==0 ||
|
||||
strcmp(opType,"ReverseBytesL")==0 ||
|
||||
@ -4175,7 +4176,7 @@ bool MatchRule::is_vector() const {
|
||||
"URShiftVB","URShiftVS","URShiftVI","URShiftVL",
|
||||
"MaxReductionV", "MinReductionV",
|
||||
"ReplicateB","ReplicateS","ReplicateI","ReplicateL","ReplicateF","ReplicateD",
|
||||
"LoadVector","StoreVector",
|
||||
"RoundDoubleModeV","LoadVector","StoreVector",
|
||||
"FmaVD", "FmaVF","PopCountVI",
|
||||
// Next are not supported currently.
|
||||
"PackB","PackS","PackI","PackL","PackF","PackD","Pack2L","Pack2D",
|
||||
|
@ -575,6 +575,9 @@ bool vmIntrinsics::is_disabled_by_flags(vmIntrinsics::ID id) {
|
||||
case vmIntrinsics::_intBitsToFloat:
|
||||
case vmIntrinsics::_doubleToRawLongBits:
|
||||
case vmIntrinsics::_longBitsToDouble:
|
||||
case vmIntrinsics::_ceil:
|
||||
case vmIntrinsics::_floor:
|
||||
case vmIntrinsics::_rint:
|
||||
case vmIntrinsics::_dabs:
|
||||
case vmIntrinsics::_fabs:
|
||||
case vmIntrinsics::_iabs:
|
||||
|
@ -766,6 +766,7 @@
|
||||
do_name(tan_name,"tan") do_name(atan2_name,"atan2") do_name(sqrt_name,"sqrt") \
|
||||
do_name(log_name,"log") do_name(log10_name,"log10") do_name(pow_name,"pow") \
|
||||
do_name(exp_name,"exp") do_name(min_name,"min") do_name(max_name,"max") \
|
||||
do_name(floor_name, "floor") do_name(ceil_name, "ceil") do_name(rint_name, "rint") \
|
||||
\
|
||||
do_name(addExact_name,"addExact") \
|
||||
do_name(decrementExact_name,"decrementExact") \
|
||||
@ -781,6 +782,9 @@
|
||||
do_intrinsic(_iabs, java_lang_Math, abs_name, int_int_signature, F_S) \
|
||||
do_intrinsic(_labs, java_lang_Math, abs_name, long_long_signature, F_S) \
|
||||
do_intrinsic(_dsin, java_lang_Math, sin_name, double_double_signature, F_S) \
|
||||
do_intrinsic(_floor, java_lang_Math, floor_name, double_double_signature, F_S) \
|
||||
do_intrinsic(_ceil, java_lang_Math, ceil_name, double_double_signature, F_S) \
|
||||
do_intrinsic(_rint, java_lang_Math, rint_name, double_double_signature, F_S) \
|
||||
do_intrinsic(_dcos, java_lang_Math, cos_name, double_double_signature, F_S) \
|
||||
do_intrinsic(_dtan, java_lang_Math, tan_name, double_double_signature, F_S) \
|
||||
do_intrinsic(_datan2, java_lang_Math, atan2_name, double2_double_signature, F_S) \
|
||||
|
@ -462,6 +462,11 @@ bool C2Compiler::is_intrinsic_supported(const methodHandle& method, bool is_virt
|
||||
case vmIntrinsics::_writebackPostSync0:
|
||||
if (!Matcher::match_rule_supported(Op_CacheWBPostSync)) return false;
|
||||
break;
|
||||
case vmIntrinsics::_rint:
|
||||
case vmIntrinsics::_ceil:
|
||||
case vmIntrinsics::_floor:
|
||||
if (!Matcher::match_rule_supported(Op_RoundDoubleMode)) return false;
|
||||
break;
|
||||
case vmIntrinsics::_hashCode:
|
||||
case vmIntrinsics::_identityHashCode:
|
||||
case vmIntrinsics::_getClass:
|
||||
|
@ -274,6 +274,8 @@ macro(Rethrow)
|
||||
macro(Return)
|
||||
macro(Root)
|
||||
macro(RoundDouble)
|
||||
macro(RoundDoubleMode)
|
||||
macro(RoundDoubleModeV)
|
||||
macro(RoundFloat)
|
||||
macro(SafePoint)
|
||||
macro(SafePointScalarObject)
|
||||
|
@ -531,4 +531,16 @@ const Type* RoundDoubleNode::Value(PhaseGVN* phase) const {
|
||||
return phase->type( in(1) );
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//------------------------------Identity---------------------------------------
|
||||
// Remove redundant roundings.
|
||||
Node* RoundDoubleModeNode::Identity(PhaseGVN* phase) {
|
||||
int op = in(1)->Opcode();
|
||||
// Redundant rounding e.g. floor(ceil(n)) -> ceil(n)
|
||||
if(op == Op_RoundDoubleMode) return in(1);
|
||||
return this;
|
||||
}
|
||||
const Type* RoundDoubleModeNode::Value(PhaseGVN* phase) const {
|
||||
return Type::DOUBLE;
|
||||
}
|
||||
//=============================================================================
|
||||
|
@ -212,5 +212,16 @@ class RoundDoubleNode: public Node {
|
||||
virtual const Type* Value(PhaseGVN* phase) const;
|
||||
};
|
||||
|
||||
//-----------------------------RoundDoubleModeNode-----------------------------
|
||||
class RoundDoubleModeNode: public Node {
|
||||
public:
|
||||
RoundDoubleModeNode(Node *in1, Node * rmode): Node(0, in1, rmode) {}
|
||||
virtual int Opcode() const;
|
||||
virtual const Type *bottom_type() const { return Type::DOUBLE; }
|
||||
virtual uint ideal_reg() const { return Op_RegD; }
|
||||
virtual Node* Identity(PhaseGVN* phase);
|
||||
virtual const Type* Value(PhaseGVN* phase) const;
|
||||
};
|
||||
|
||||
|
||||
#endif // SHARE_OPTO_CONVERTNODE_HPP
|
||||
|
@ -534,6 +534,9 @@ bool LibraryCallKit::try_to_inline(int predicate) {
|
||||
case vmIntrinsics::_identityHashCode: return inline_native_hashcode(/*!virtual*/ false, is_static);
|
||||
case vmIntrinsics::_getClass: return inline_native_getClass();
|
||||
|
||||
case vmIntrinsics::_ceil:
|
||||
case vmIntrinsics::_floor:
|
||||
case vmIntrinsics::_rint:
|
||||
case vmIntrinsics::_dsin:
|
||||
case vmIntrinsics::_dcos:
|
||||
case vmIntrinsics::_dtan:
|
||||
@ -1818,6 +1821,9 @@ bool LibraryCallKit::inline_double_math(vmIntrinsics::ID id) {
|
||||
switch (id) {
|
||||
case vmIntrinsics::_dabs: n = new AbsDNode( arg); break;
|
||||
case vmIntrinsics::_dsqrt: n = new SqrtDNode(C, control(), arg); break;
|
||||
case vmIntrinsics::_ceil: n = new RoundDoubleModeNode(arg, makecon(TypeInt::make(2))); break;
|
||||
case vmIntrinsics::_floor: n = new RoundDoubleModeNode(arg, makecon(TypeInt::make(1))); break;
|
||||
case vmIntrinsics::_rint: n = new RoundDoubleModeNode(arg, makecon(TypeInt::make(0))); break;
|
||||
default: fatal_unexpected_iid(id); break;
|
||||
}
|
||||
set_result(_gvn.transform(n));
|
||||
@ -1891,6 +1897,9 @@ bool LibraryCallKit::inline_math_native(vmIntrinsics::ID id) {
|
||||
runtime_math(OptoRuntime::Math_D_D_Type(), FN_PTR(SharedRuntime::dlog10), "LOG10");
|
||||
|
||||
// These intrinsics are supported on all hardware
|
||||
case vmIntrinsics::_ceil:
|
||||
case vmIntrinsics::_floor:
|
||||
case vmIntrinsics::_rint: return Matcher::match_rule_supported(Op_RoundDoubleMode) ? inline_double_math(id) : false;
|
||||
case vmIntrinsics::_dsqrt: return Matcher::match_rule_supported(Op_SqrtD) ? inline_double_math(id) : false;
|
||||
case vmIntrinsics::_dabs: return Matcher::has_match_rule(Op_AbsD) ? inline_double_math(id) : false;
|
||||
case vmIntrinsics::_fabs: return Matcher::match_rule_supported(Op_AbsF) ? inline_math(id) : false;
|
||||
|
@ -2401,6 +2401,12 @@ void SuperWord::output() {
|
||||
const TypePtr* atyp = n->adr_type();
|
||||
vn = StoreVectorNode::make(opc, ctl, mem, adr, atyp, val, vlen);
|
||||
vlen_in_bytes = vn->as_StoreVector()->memory_size();
|
||||
} else if (VectorNode::is_roundopD(n)) {
|
||||
Node* in1 = vector_opd(p, 1);
|
||||
Node* in2 = low_adr->in(2);
|
||||
assert(in2->is_Con(), "Constant rounding mode expected.");
|
||||
vn = VectorNode::make(opc, in1, in2, vlen, velt_basic_type(n));
|
||||
vlen_in_bytes = vn->as_Vector()->length_in_bytes();
|
||||
} else if (VectorNode::is_muladds2i(n)) {
|
||||
assert(n->req() == 5u, "MulAddS2I should have 4 operands.");
|
||||
Node* in1 = vector_opd(p, 1);
|
||||
|
@ -128,6 +128,9 @@ int VectorNode::opcode(int sopc, BasicType bt) {
|
||||
case Op_NegD:
|
||||
assert(bt == T_DOUBLE, "must be");
|
||||
return Op_NegVD;
|
||||
case Op_RoundDoubleMode:
|
||||
assert(bt == T_DOUBLE, "must be");
|
||||
return Op_RoundDoubleModeV;
|
||||
case Op_SqrtF:
|
||||
assert(bt == T_FLOAT, "must be");
|
||||
return Op_SqrtVF;
|
||||
@ -259,6 +262,13 @@ bool VectorNode::is_muladds2i(Node* n) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool VectorNode::is_roundopD(Node *n) {
|
||||
if (n->Opcode() == Op_RoundDoubleMode) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool VectorNode::is_shift(Node* n) {
|
||||
switch (n->Opcode()) {
|
||||
case Op_LShiftI:
|
||||
@ -407,6 +417,8 @@ VectorNode* VectorNode::make(int opc, Node* n1, Node* n2, uint vlen, BasicType b
|
||||
case Op_MinV: return new MinVNode(n1, n2, vt);
|
||||
case Op_MaxV: return new MaxVNode(n1, n2, vt);
|
||||
|
||||
case Op_RoundDoubleModeV: return new RoundDoubleModeVNode(n1, n2, vt);
|
||||
|
||||
case Op_MulAddVS2VI: return new MulAddVS2VINode(n1, n2, vt);
|
||||
default:
|
||||
fatal("Missed vector creation for '%s'", NodeClassNames[vopc]);
|
||||
|
@ -70,6 +70,7 @@ class VectorNode : public TypeNode {
|
||||
static bool is_type_transition_short_to_int(Node* n);
|
||||
static bool is_type_transition_to_int(Node* n);
|
||||
static bool is_muladds2i(Node* n);
|
||||
static bool is_roundopD(Node * n);
|
||||
static bool is_invariant_vector(Node* n);
|
||||
// [Start, end) half-open range defining which operands are vectors
|
||||
static void vector_operands(Node* n, uint* start, uint* end);
|
||||
@ -447,6 +448,13 @@ class SqrtVFNode : public VectorNode {
|
||||
SqrtVFNode(Node* in, const TypeVect* vt) : VectorNode(in,vt) {}
|
||||
virtual int Opcode() const;
|
||||
};
|
||||
//------------------------------RoundDoubleVNode--------------------------------
|
||||
// Vector round double
|
||||
class RoundDoubleModeVNode : public VectorNode {
|
||||
public:
|
||||
RoundDoubleModeVNode(Node* in1, Node* in2, const TypeVect* vt) : VectorNode(in1, in2, vt) {}
|
||||
virtual int Opcode() const;
|
||||
};
|
||||
|
||||
//------------------------------SqrtVDNode--------------------------------------
|
||||
// Vector Sqrt double
|
||||
|
@ -440,6 +440,7 @@ public final class Math {
|
||||
* floating-point value that is greater than or equal to
|
||||
* the argument and is equal to a mathematical integer.
|
||||
*/
|
||||
@HotSpotIntrinsicCandidate
|
||||
public static double ceil(double a) {
|
||||
return StrictMath.ceil(a); // default impl. delegates to StrictMath
|
||||
}
|
||||
@ -459,6 +460,7 @@ public final class Math {
|
||||
* floating-point value that less than or equal to the argument
|
||||
* and is equal to a mathematical integer.
|
||||
*/
|
||||
@HotSpotIntrinsicCandidate
|
||||
public static double floor(double a) {
|
||||
return StrictMath.floor(a); // default impl. delegates to StrictMath
|
||||
}
|
||||
@ -478,6 +480,7 @@ public final class Math {
|
||||
* @return the closest floating-point value to {@code a} that is
|
||||
* equal to a mathematical integer.
|
||||
*/
|
||||
@HotSpotIntrinsicCandidate
|
||||
public static double rint(double a) {
|
||||
return StrictMath.rint(a); // default impl. delegates to StrictMath
|
||||
}
|
||||
|
@ -87,6 +87,9 @@ public class TestDoubleVect {
|
||||
test_divv(a0, a1, -VALUE);
|
||||
test_diva(a0, a1, a3);
|
||||
test_negc(a0, a1);
|
||||
test_rint(a0, a1);
|
||||
test_ceil(a0, a1);
|
||||
test_floor(a0, a1);
|
||||
}
|
||||
// Test and verify results
|
||||
System.out.println("Verification");
|
||||
@ -351,6 +354,56 @@ public class TestDoubleVect {
|
||||
errn += verify("test_negc: ", i, a0[i], (double)(-((double)(ADD_INIT+i))));
|
||||
}
|
||||
|
||||
// To test -ve and +ve Zero scenarios.
|
||||
double [] other_corner_cases = { -0.0, 0.0, 9.007199254740992E15 };
|
||||
double [] other_corner_cases_res = new double[3];
|
||||
test_floor(a0, a1);
|
||||
errn += verify("test_floor: ", 0, a0[0], Double.NaN);
|
||||
errn += verify("test_floor: ", 1, a0[1], Double.POSITIVE_INFINITY);
|
||||
errn += verify("test_floor: ", 2, a0[2], Double.NEGATIVE_INFINITY);
|
||||
errn += verify("test_floor: ", 3, a0[3], Double.MAX_VALUE);
|
||||
errn += verify("test_floor: ", 4, a0[4], 0.0);
|
||||
errn += verify("test_floor: ", 5, a0[5], 0.0);
|
||||
for (int i=6; i<ARRLEN; i++) {
|
||||
errn += verify("test_floor: ", i, a0[i], ((double)(ADD_INIT+i)));
|
||||
}
|
||||
test_floor_cc(other_corner_cases_res, other_corner_cases);
|
||||
errn += verify("test_floor_cc: ", 0, other_corner_cases_res[0], -0.0);
|
||||
errn += verify("test_floor_cc: ", 1, other_corner_cases_res[1], 0.0);
|
||||
errn += verify("test_floor_cc: ", 2, other_corner_cases_res[2], 9.007199254740992E15);
|
||||
|
||||
test_ceil(a0, a1);
|
||||
errn += verify("test_ceil: ", 0, a0[0], Double.NaN);
|
||||
errn += verify("test_ceil: ", 1, a0[1], Double.POSITIVE_INFINITY);
|
||||
errn += verify("test_ceil: ", 2, a0[2], Double.NEGATIVE_INFINITY);
|
||||
errn += verify("test_ceil: ", 3, a0[3], Double.MAX_VALUE);
|
||||
errn += verify("test_ceil: ", 4, a0[4], 1.0);
|
||||
errn += verify("test_ceil: ", 5, a0[5], 1.0);
|
||||
for (int i=6; i<ARRLEN; i++) {
|
||||
errn += verify("test_ceil: ", i, a0[i], ((double)(ADD_INIT+i+1.0)));
|
||||
}
|
||||
test_ceil_cc(other_corner_cases_res, other_corner_cases);
|
||||
errn += verify("test_ceil_cc: ", 0, other_corner_cases_res[0], -0.0);
|
||||
errn += verify("test_ceil_cc: ", 1, other_corner_cases_res[1], 0.0);
|
||||
errn += verify("test_ceil_cc: ", 2, other_corner_cases_res[2], 9.007199254740992E15);
|
||||
|
||||
test_rint(a0, a1);
|
||||
errn += verify("test_rint: ", 0, a0[0], Double.NaN);
|
||||
errn += verify("test_rint: ", 1, a0[1], Double.POSITIVE_INFINITY);
|
||||
errn += verify("test_rint: ", 2, a0[2], Double.NEGATIVE_INFINITY);
|
||||
errn += verify("test_rint: ", 3, a0[3], Double.MAX_VALUE);
|
||||
errn += verify("test_rint: ", 4, a0[4], 0.0);
|
||||
errn += verify("test_rint: ", 5, a0[5], 0.0);
|
||||
for (int i=6; i<ARRLEN; i++) {
|
||||
if ( i <= 500 )
|
||||
errn += verify("test_rint: ", i, a0[i], ((double)(ADD_INIT+i)));
|
||||
else
|
||||
errn += verify("test_rint: ", i, a0[i], ((double)(ADD_INIT+i+1.0)));
|
||||
}
|
||||
test_rint_cc(other_corner_cases_res, other_corner_cases);
|
||||
errn += verify("test_rint_cc: ", 0, other_corner_cases_res[0], -0.0);
|
||||
errn += verify("test_rint_cc: ", 1, other_corner_cases_res[1], 0.0);
|
||||
errn += verify("test_rint_cc: ", 2, other_corner_cases_res[2], 9.007199254740992E15);
|
||||
}
|
||||
|
||||
if (errn > 0)
|
||||
@ -577,6 +630,37 @@ public class TestDoubleVect {
|
||||
}
|
||||
}
|
||||
|
||||
static void test_rint(double[] a0, double[] a1) {
|
||||
for (int i = 0; i < a0.length; i+=1) {
|
||||
a0[i] = Math.rint(a1[i] + ((double)(i))/1000);
|
||||
}
|
||||
}
|
||||
static void test_ceil(double[] a0, double[] a1) {
|
||||
for (int i = 0; i < a0.length; i+=1) {
|
||||
a0[i] = Math.ceil(a1[i] + ((double)(i))/1000);
|
||||
}
|
||||
}
|
||||
static void test_floor(double[] a0, double[] a1) {
|
||||
for (int i = 0; i < a0.length; i+=1) {
|
||||
a0[i] = Math.floor(a1[i] + ((double)(i))/1000);
|
||||
}
|
||||
}
|
||||
static void test_rint_cc(double[] a0, double[] a1) {
|
||||
for (int i = 0; i < a0.length; i+=1) {
|
||||
a0[i] = Math.rint(a1[i]);
|
||||
}
|
||||
}
|
||||
static void test_ceil_cc(double[] a0, double[] a1) {
|
||||
for (int i = 0; i < a0.length; i+=1) {
|
||||
a0[i] = Math.ceil(a1[i]);
|
||||
}
|
||||
}
|
||||
static void test_floor_cc(double[] a0, double[] a1) {
|
||||
for (int i = 0; i < a0.length; i+=1) {
|
||||
a0[i] = Math.floor(a1[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static int verify(String text, int i, double elem, double val) {
|
||||
if (elem != val && !(Double.isNaN(elem) && Double.isNaN(val))) {
|
||||
System.err.println(text + "[" + i + "] = " + elem + " != " + val);
|
||||
|
@ -0,0 +1,78 @@
|
||||
//
|
||||
// Copyright (c) 2003, 2019, 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.java.math;
|
||||
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.openjdk.jmh.annotations.*;
|
||||
import org.openjdk.jmh.infra.Blackhole;
|
||||
|
||||
@OutputTimeUnit(TimeUnit.MILLISECONDS)
|
||||
@State(Scope.Thread)
|
||||
public class FpRoundingBenchmark {
|
||||
|
||||
@Param({"1024"})
|
||||
public int TESTSIZE;
|
||||
|
||||
public double[] DargV1;
|
||||
|
||||
public double[] Res;
|
||||
|
||||
public final double[] DspecialVals = {
|
||||
0.0, -0.0, Double.NaN, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY};
|
||||
|
||||
@Setup(Level.Trial)
|
||||
public void BmSetup() {
|
||||
int i = 0;
|
||||
Random r = new Random(1024);
|
||||
DargV1 = new double[TESTSIZE];
|
||||
Res = new double[TESTSIZE];
|
||||
|
||||
for (; i < DspecialVals.length; i++) {
|
||||
DargV1[i] = DspecialVals[i];
|
||||
}
|
||||
|
||||
for (; i < TESTSIZE; i++) {
|
||||
DargV1[i] = r.nextDouble()*TESTSIZE;
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void testceil(Blackhole bh) {
|
||||
for (int i = 0; i < TESTSIZE; i++)
|
||||
Res[i] = Math.ceil(DargV1[i]);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void testfloor(Blackhole bh) {
|
||||
for (int i = 0; i < TESTSIZE; i++)
|
||||
Res[i] = Math.floor(DargV1[i]);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void testrint(Blackhole bh) {
|
||||
for (int i = 0; i < TESTSIZE; i++)
|
||||
Res[i] = Math.rint(DargV1[i]);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user