8226721: Missing intrinsics for Math.ceil, floor, rint

Reviewed-by: neliasso, vlivanov, ecaspole
This commit is contained in:
Jatin Bhateja 2019-10-01 11:43:10 +02:00 committed by Nils Eliasson
parent 09c012be4e
commit d3ca3a02ff
19 changed files with 434 additions and 2 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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));

View File

@ -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);

View File

@ -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);

View File

@ -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",

View File

@ -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:

View File

@ -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) \

View File

@ -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:

View File

@ -274,6 +274,8 @@ macro(Rethrow)
macro(Return)
macro(Root)
macro(RoundDouble)
macro(RoundDoubleMode)
macro(RoundDoubleModeV)
macro(RoundFloat)
macro(SafePoint)
macro(SafePointScalarObject)

View File

@ -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;
}
//=============================================================================

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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]);

View File

@ -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

View File

@ -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
}

View File

@ -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);

View File

@ -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]);
}
}