mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 23:34:52 +02:00
8285973: x86_64: Improve fp comparison and cmove for eq/ne
Reviewed-by: kvn, sviswanathan
This commit is contained in:
parent
782ae3801c
commit
c1db70d827
4 changed files with 634 additions and 84 deletions
|
@ -4268,30 +4268,33 @@ operand cmpOpU()
|
||||||
equal(0x4, "e");
|
equal(0x4, "e");
|
||||||
not_equal(0x5, "ne");
|
not_equal(0x5, "ne");
|
||||||
less(0x2, "b");
|
less(0x2, "b");
|
||||||
greater_equal(0x3, "nb");
|
greater_equal(0x3, "ae");
|
||||||
less_equal(0x6, "be");
|
less_equal(0x6, "be");
|
||||||
greater(0x7, "nbe");
|
greater(0x7, "a");
|
||||||
overflow(0x0, "o");
|
overflow(0x0, "o");
|
||||||
no_overflow(0x1, "no");
|
no_overflow(0x1, "no");
|
||||||
%}
|
%}
|
||||||
%}
|
%}
|
||||||
|
|
||||||
|
|
||||||
// Floating comparisons that don't require any fixup for the unordered case
|
// Floating comparisons that don't require any fixup for the unordered case,
|
||||||
|
// If both inputs of the comparison are the same, ZF is always set so we
|
||||||
|
// don't need to use cmpOpUCF2 for eq/ne
|
||||||
operand cmpOpUCF() %{
|
operand cmpOpUCF() %{
|
||||||
match(Bool);
|
match(Bool);
|
||||||
predicate(n->as_Bool()->_test._test == BoolTest::lt ||
|
predicate(n->as_Bool()->_test._test == BoolTest::lt ||
|
||||||
n->as_Bool()->_test._test == BoolTest::ge ||
|
n->as_Bool()->_test._test == BoolTest::ge ||
|
||||||
n->as_Bool()->_test._test == BoolTest::le ||
|
n->as_Bool()->_test._test == BoolTest::le ||
|
||||||
n->as_Bool()->_test._test == BoolTest::gt);
|
n->as_Bool()->_test._test == BoolTest::gt ||
|
||||||
|
n->in(1)->in(1) == n->in(1)->in(2));
|
||||||
format %{ "" %}
|
format %{ "" %}
|
||||||
interface(COND_INTER) %{
|
interface(COND_INTER) %{
|
||||||
equal(0x4, "e");
|
equal(0xb, "np");
|
||||||
not_equal(0x5, "ne");
|
not_equal(0xa, "p");
|
||||||
less(0x2, "b");
|
less(0x2, "b");
|
||||||
greater_equal(0x3, "nb");
|
greater_equal(0x3, "ae");
|
||||||
less_equal(0x6, "be");
|
less_equal(0x6, "be");
|
||||||
greater(0x7, "nbe");
|
greater(0x7, "a");
|
||||||
overflow(0x0, "o");
|
overflow(0x0, "o");
|
||||||
no_overflow(0x1, "no");
|
no_overflow(0x1, "no");
|
||||||
%}
|
%}
|
||||||
|
@ -4301,16 +4304,17 @@ operand cmpOpUCF() %{
|
||||||
// Floating comparisons that can be fixed up with extra conditional jumps
|
// Floating comparisons that can be fixed up with extra conditional jumps
|
||||||
operand cmpOpUCF2() %{
|
operand cmpOpUCF2() %{
|
||||||
match(Bool);
|
match(Bool);
|
||||||
predicate(n->as_Bool()->_test._test == BoolTest::ne ||
|
predicate((n->as_Bool()->_test._test == BoolTest::ne ||
|
||||||
n->as_Bool()->_test._test == BoolTest::eq);
|
n->as_Bool()->_test._test == BoolTest::eq) &&
|
||||||
|
n->in(1)->in(1) != n->in(1)->in(2));
|
||||||
format %{ "" %}
|
format %{ "" %}
|
||||||
interface(COND_INTER) %{
|
interface(COND_INTER) %{
|
||||||
equal(0x4, "e");
|
equal(0x4, "e");
|
||||||
not_equal(0x5, "ne");
|
not_equal(0x5, "ne");
|
||||||
less(0x2, "b");
|
less(0x2, "b");
|
||||||
greater_equal(0x3, "nb");
|
greater_equal(0x3, "ae");
|
||||||
less_equal(0x6, "be");
|
less_equal(0x6, "be");
|
||||||
greater(0x7, "nbe");
|
greater(0x7, "a");
|
||||||
overflow(0x0, "o");
|
overflow(0x0, "o");
|
||||||
no_overflow(0x1, "no");
|
no_overflow(0x1, "no");
|
||||||
%}
|
%}
|
||||||
|
@ -7037,6 +7041,36 @@ instruct cmovI_regUCF(cmpOpUCF cop, rFlagsRegUCF cr, rRegI dst, rRegI src) %{
|
||||||
%}
|
%}
|
||||||
%}
|
%}
|
||||||
|
|
||||||
|
instruct cmovI_regUCF2_ne(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegI dst, rRegI src) %{
|
||||||
|
predicate(n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::ne);
|
||||||
|
match(Set dst (CMoveI (Binary cop cr) (Binary dst src)));
|
||||||
|
|
||||||
|
ins_cost(200); // XXX
|
||||||
|
format %{ "cmovpl $dst, $src\n\t"
|
||||||
|
"cmovnel $dst, $src" %}
|
||||||
|
ins_encode %{
|
||||||
|
__ cmovl(Assembler::parity, $dst$$Register, $src$$Register);
|
||||||
|
__ cmovl(Assembler::notEqual, $dst$$Register, $src$$Register);
|
||||||
|
%}
|
||||||
|
ins_pipe(pipe_cmov_reg);
|
||||||
|
%}
|
||||||
|
|
||||||
|
// Since (x == y) == !(x != y), we can flip the sense of the test by flipping the
|
||||||
|
// inputs of the CMove
|
||||||
|
instruct cmovI_regUCF2_eq(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegI dst, rRegI src) %{
|
||||||
|
predicate(n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::eq);
|
||||||
|
match(Set dst (CMoveI (Binary cop cr) (Binary src dst)));
|
||||||
|
|
||||||
|
ins_cost(200); // XXX
|
||||||
|
format %{ "cmovpl $dst, $src\n\t"
|
||||||
|
"cmovnel $dst, $src" %}
|
||||||
|
ins_encode %{
|
||||||
|
__ cmovl(Assembler::parity, $dst$$Register, $src$$Register);
|
||||||
|
__ cmovl(Assembler::notEqual, $dst$$Register, $src$$Register);
|
||||||
|
%}
|
||||||
|
ins_pipe(pipe_cmov_reg);
|
||||||
|
%}
|
||||||
|
|
||||||
// Conditional move
|
// Conditional move
|
||||||
instruct cmovI_mem(cmpOp cop, rFlagsReg cr, rRegI dst, memory src) %{
|
instruct cmovI_mem(cmpOp cop, rFlagsReg cr, rRegI dst, memory src) %{
|
||||||
match(Set dst (CMoveI (Binary cop cr) (Binary dst (LoadI src))));
|
match(Set dst (CMoveI (Binary cop cr) (Binary dst (LoadI src))));
|
||||||
|
@ -7104,6 +7138,36 @@ instruct cmovN_regUCF(cmpOpUCF cop, rFlagsRegUCF cr, rRegN dst, rRegN src) %{
|
||||||
%}
|
%}
|
||||||
%}
|
%}
|
||||||
|
|
||||||
|
instruct cmovN_regUCF2_ne(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegN dst, rRegN src) %{
|
||||||
|
predicate(n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::ne);
|
||||||
|
match(Set dst (CMoveN (Binary cop cr) (Binary dst src)));
|
||||||
|
|
||||||
|
ins_cost(200); // XXX
|
||||||
|
format %{ "cmovpl $dst, $src\n\t"
|
||||||
|
"cmovnel $dst, $src" %}
|
||||||
|
ins_encode %{
|
||||||
|
__ cmovl(Assembler::parity, $dst$$Register, $src$$Register);
|
||||||
|
__ cmovl(Assembler::notEqual, $dst$$Register, $src$$Register);
|
||||||
|
%}
|
||||||
|
ins_pipe(pipe_cmov_reg);
|
||||||
|
%}
|
||||||
|
|
||||||
|
// Since (x == y) == !(x != y), we can flip the sense of the test by flipping the
|
||||||
|
// inputs of the CMove
|
||||||
|
instruct cmovN_regUCF2_eq(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegN dst, rRegN src) %{
|
||||||
|
predicate(n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::eq);
|
||||||
|
match(Set dst (CMoveN (Binary cop cr) (Binary src dst)));
|
||||||
|
|
||||||
|
ins_cost(200); // XXX
|
||||||
|
format %{ "cmovpl $dst, $src\n\t"
|
||||||
|
"cmovnel $dst, $src" %}
|
||||||
|
ins_encode %{
|
||||||
|
__ cmovl(Assembler::parity, $dst$$Register, $src$$Register);
|
||||||
|
__ cmovl(Assembler::notEqual, $dst$$Register, $src$$Register);
|
||||||
|
%}
|
||||||
|
ins_pipe(pipe_cmov_reg);
|
||||||
|
%}
|
||||||
|
|
||||||
// Conditional move
|
// Conditional move
|
||||||
instruct cmovP_reg(rRegP dst, rRegP src, rFlagsReg cr, cmpOp cop)
|
instruct cmovP_reg(rRegP dst, rRegP src, rFlagsReg cr, cmpOp cop)
|
||||||
%{
|
%{
|
||||||
|
@ -7138,6 +7202,36 @@ instruct cmovP_regUCF(cmpOpUCF cop, rFlagsRegUCF cr, rRegP dst, rRegP src) %{
|
||||||
%}
|
%}
|
||||||
%}
|
%}
|
||||||
|
|
||||||
|
instruct cmovP_regUCF2_ne(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegP dst, rRegP src) %{
|
||||||
|
predicate(n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::ne);
|
||||||
|
match(Set dst (CMoveP (Binary cop cr) (Binary dst src)));
|
||||||
|
|
||||||
|
ins_cost(200); // XXX
|
||||||
|
format %{ "cmovpq $dst, $src\n\t"
|
||||||
|
"cmovneq $dst, $src" %}
|
||||||
|
ins_encode %{
|
||||||
|
__ cmovq(Assembler::parity, $dst$$Register, $src$$Register);
|
||||||
|
__ cmovq(Assembler::notEqual, $dst$$Register, $src$$Register);
|
||||||
|
%}
|
||||||
|
ins_pipe(pipe_cmov_reg);
|
||||||
|
%}
|
||||||
|
|
||||||
|
// Since (x == y) == !(x != y), we can flip the sense of the test by flipping the
|
||||||
|
// inputs of the CMove
|
||||||
|
instruct cmovP_regUCF2_eq(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegP dst, rRegP src) %{
|
||||||
|
predicate(n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::eq);
|
||||||
|
match(Set dst (CMoveP (Binary cop cr) (Binary src dst)));
|
||||||
|
|
||||||
|
ins_cost(200); // XXX
|
||||||
|
format %{ "cmovpq $dst, $src\n\t"
|
||||||
|
"cmovneq $dst, $src" %}
|
||||||
|
ins_encode %{
|
||||||
|
__ cmovq(Assembler::parity, $dst$$Register, $src$$Register);
|
||||||
|
__ cmovq(Assembler::notEqual, $dst$$Register, $src$$Register);
|
||||||
|
%}
|
||||||
|
ins_pipe(pipe_cmov_reg);
|
||||||
|
%}
|
||||||
|
|
||||||
// DISABLED: Requires the ADLC to emit a bottom_type call that
|
// DISABLED: Requires the ADLC to emit a bottom_type call that
|
||||||
// correctly meets the two pointer arguments; one is an incoming
|
// correctly meets the two pointer arguments; one is an incoming
|
||||||
// register but the other is a memory operand. ALSO appears to
|
// register but the other is a memory operand. ALSO appears to
|
||||||
|
@ -7209,6 +7303,36 @@ instruct cmovL_regUCF(cmpOpUCF cop, rFlagsRegUCF cr, rRegL dst, rRegL src) %{
|
||||||
%}
|
%}
|
||||||
%}
|
%}
|
||||||
|
|
||||||
|
instruct cmovL_regUCF2_ne(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegL dst, rRegL src) %{
|
||||||
|
predicate(n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::ne);
|
||||||
|
match(Set dst (CMoveL (Binary cop cr) (Binary dst src)));
|
||||||
|
|
||||||
|
ins_cost(200); // XXX
|
||||||
|
format %{ "cmovpq $dst, $src\n\t"
|
||||||
|
"cmovneq $dst, $src" %}
|
||||||
|
ins_encode %{
|
||||||
|
__ cmovq(Assembler::parity, $dst$$Register, $src$$Register);
|
||||||
|
__ cmovq(Assembler::notEqual, $dst$$Register, $src$$Register);
|
||||||
|
%}
|
||||||
|
ins_pipe(pipe_cmov_reg);
|
||||||
|
%}
|
||||||
|
|
||||||
|
// Since (x == y) == !(x != y), we can flip the sense of the test by flipping the
|
||||||
|
// inputs of the CMove
|
||||||
|
instruct cmovL_regUCF2_eq(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegL dst, rRegL src) %{
|
||||||
|
predicate(n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::eq);
|
||||||
|
match(Set dst (CMoveL (Binary cop cr) (Binary src dst)));
|
||||||
|
|
||||||
|
ins_cost(200); // XXX
|
||||||
|
format %{ "cmovpq $dst, $src\n\t"
|
||||||
|
"cmovneq $dst, $src" %}
|
||||||
|
ins_encode %{
|
||||||
|
__ cmovq(Assembler::parity, $dst$$Register, $src$$Register);
|
||||||
|
__ cmovq(Assembler::notEqual, $dst$$Register, $src$$Register);
|
||||||
|
%}
|
||||||
|
ins_pipe(pipe_cmov_reg);
|
||||||
|
%}
|
||||||
|
|
||||||
instruct cmovL_memU(cmpOpU cop, rFlagsRegU cr, rRegL dst, memory src)
|
instruct cmovL_memU(cmpOpU cop, rFlagsRegU cr, rRegL dst, memory src)
|
||||||
%{
|
%{
|
||||||
match(Set dst (CMoveL (Binary cop cr) (Binary dst (LoadL src))));
|
match(Set dst (CMoveL (Binary cop cr) (Binary dst (LoadL src))));
|
||||||
|
@ -10479,11 +10603,12 @@ instruct and_cmpLTMask(rRegI p, rRegI q, rRegI y, rFlagsReg cr)
|
||||||
|
|
||||||
//---------- FP Instructions------------------------------------------------
|
//---------- FP Instructions------------------------------------------------
|
||||||
|
|
||||||
|
// Really expensive, avoid
|
||||||
instruct cmpF_cc_reg(rFlagsRegU cr, regF src1, regF src2)
|
instruct cmpF_cc_reg(rFlagsRegU cr, regF src1, regF src2)
|
||||||
%{
|
%{
|
||||||
match(Set cr (CmpF src1 src2));
|
match(Set cr (CmpF src1 src2));
|
||||||
|
|
||||||
ins_cost(145);
|
ins_cost(500);
|
||||||
format %{ "ucomiss $src1, $src2\n\t"
|
format %{ "ucomiss $src1, $src2\n\t"
|
||||||
"jnp,s exit\n\t"
|
"jnp,s exit\n\t"
|
||||||
"pushfq\t# saw NaN, set CF\n\t"
|
"pushfq\t# saw NaN, set CF\n\t"
|
||||||
|
@ -10508,24 +10633,6 @@ instruct cmpF_cc_reg_CF(rFlagsRegUCF cr, regF src1, regF src2) %{
|
||||||
ins_pipe(pipe_slow);
|
ins_pipe(pipe_slow);
|
||||||
%}
|
%}
|
||||||
|
|
||||||
instruct cmpF_cc_mem(rFlagsRegU cr, regF src1, memory src2)
|
|
||||||
%{
|
|
||||||
match(Set cr (CmpF src1 (LoadF src2)));
|
|
||||||
|
|
||||||
ins_cost(145);
|
|
||||||
format %{ "ucomiss $src1, $src2\n\t"
|
|
||||||
"jnp,s exit\n\t"
|
|
||||||
"pushfq\t# saw NaN, set CF\n\t"
|
|
||||||
"andq [rsp], #0xffffff2b\n\t"
|
|
||||||
"popfq\n"
|
|
||||||
"exit:" %}
|
|
||||||
ins_encode %{
|
|
||||||
__ ucomiss($src1$$XMMRegister, $src2$$Address);
|
|
||||||
emit_cmpfp_fixup(_masm);
|
|
||||||
%}
|
|
||||||
ins_pipe(pipe_slow);
|
|
||||||
%}
|
|
||||||
|
|
||||||
instruct cmpF_cc_memCF(rFlagsRegUCF cr, regF src1, memory src2) %{
|
instruct cmpF_cc_memCF(rFlagsRegUCF cr, regF src1, memory src2) %{
|
||||||
match(Set cr (CmpF src1 (LoadF src2)));
|
match(Set cr (CmpF src1 (LoadF src2)));
|
||||||
|
|
||||||
|
@ -10537,23 +10644,6 @@ instruct cmpF_cc_memCF(rFlagsRegUCF cr, regF src1, memory src2) %{
|
||||||
ins_pipe(pipe_slow);
|
ins_pipe(pipe_slow);
|
||||||
%}
|
%}
|
||||||
|
|
||||||
instruct cmpF_cc_imm(rFlagsRegU cr, regF src, immF con) %{
|
|
||||||
match(Set cr (CmpF src con));
|
|
||||||
|
|
||||||
ins_cost(145);
|
|
||||||
format %{ "ucomiss $src, [$constantaddress]\t# load from constant table: float=$con\n\t"
|
|
||||||
"jnp,s exit\n\t"
|
|
||||||
"pushfq\t# saw NaN, set CF\n\t"
|
|
||||||
"andq [rsp], #0xffffff2b\n\t"
|
|
||||||
"popfq\n"
|
|
||||||
"exit:" %}
|
|
||||||
ins_encode %{
|
|
||||||
__ ucomiss($src$$XMMRegister, $constantaddress($con));
|
|
||||||
emit_cmpfp_fixup(_masm);
|
|
||||||
%}
|
|
||||||
ins_pipe(pipe_slow);
|
|
||||||
%}
|
|
||||||
|
|
||||||
instruct cmpF_cc_immCF(rFlagsRegUCF cr, regF src, immF con) %{
|
instruct cmpF_cc_immCF(rFlagsRegUCF cr, regF src, immF con) %{
|
||||||
match(Set cr (CmpF src con));
|
match(Set cr (CmpF src con));
|
||||||
ins_cost(100);
|
ins_cost(100);
|
||||||
|
@ -10564,11 +10654,12 @@ instruct cmpF_cc_immCF(rFlagsRegUCF cr, regF src, immF con) %{
|
||||||
ins_pipe(pipe_slow);
|
ins_pipe(pipe_slow);
|
||||||
%}
|
%}
|
||||||
|
|
||||||
|
// Really expensive, avoid
|
||||||
instruct cmpD_cc_reg(rFlagsRegU cr, regD src1, regD src2)
|
instruct cmpD_cc_reg(rFlagsRegU cr, regD src1, regD src2)
|
||||||
%{
|
%{
|
||||||
match(Set cr (CmpD src1 src2));
|
match(Set cr (CmpD src1 src2));
|
||||||
|
|
||||||
ins_cost(145);
|
ins_cost(500);
|
||||||
format %{ "ucomisd $src1, $src2\n\t"
|
format %{ "ucomisd $src1, $src2\n\t"
|
||||||
"jnp,s exit\n\t"
|
"jnp,s exit\n\t"
|
||||||
"pushfq\t# saw NaN, set CF\n\t"
|
"pushfq\t# saw NaN, set CF\n\t"
|
||||||
|
@ -10593,24 +10684,6 @@ instruct cmpD_cc_reg_CF(rFlagsRegUCF cr, regD src1, regD src2) %{
|
||||||
ins_pipe(pipe_slow);
|
ins_pipe(pipe_slow);
|
||||||
%}
|
%}
|
||||||
|
|
||||||
instruct cmpD_cc_mem(rFlagsRegU cr, regD src1, memory src2)
|
|
||||||
%{
|
|
||||||
match(Set cr (CmpD src1 (LoadD src2)));
|
|
||||||
|
|
||||||
ins_cost(145);
|
|
||||||
format %{ "ucomisd $src1, $src2\n\t"
|
|
||||||
"jnp,s exit\n\t"
|
|
||||||
"pushfq\t# saw NaN, set CF\n\t"
|
|
||||||
"andq [rsp], #0xffffff2b\n\t"
|
|
||||||
"popfq\n"
|
|
||||||
"exit:" %}
|
|
||||||
ins_encode %{
|
|
||||||
__ ucomisd($src1$$XMMRegister, $src2$$Address);
|
|
||||||
emit_cmpfp_fixup(_masm);
|
|
||||||
%}
|
|
||||||
ins_pipe(pipe_slow);
|
|
||||||
%}
|
|
||||||
|
|
||||||
instruct cmpD_cc_memCF(rFlagsRegUCF cr, regD src1, memory src2) %{
|
instruct cmpD_cc_memCF(rFlagsRegUCF cr, regD src1, memory src2) %{
|
||||||
match(Set cr (CmpD src1 (LoadD src2)));
|
match(Set cr (CmpD src1 (LoadD src2)));
|
||||||
|
|
||||||
|
@ -10622,23 +10695,6 @@ instruct cmpD_cc_memCF(rFlagsRegUCF cr, regD src1, memory src2) %{
|
||||||
ins_pipe(pipe_slow);
|
ins_pipe(pipe_slow);
|
||||||
%}
|
%}
|
||||||
|
|
||||||
instruct cmpD_cc_imm(rFlagsRegU cr, regD src, immD con) %{
|
|
||||||
match(Set cr (CmpD src con));
|
|
||||||
|
|
||||||
ins_cost(145);
|
|
||||||
format %{ "ucomisd $src, [$constantaddress]\t# load from constant table: double=$con\n\t"
|
|
||||||
"jnp,s exit\n\t"
|
|
||||||
"pushfq\t# saw NaN, set CF\n\t"
|
|
||||||
"andq [rsp], #0xffffff2b\n\t"
|
|
||||||
"popfq\n"
|
|
||||||
"exit:" %}
|
|
||||||
ins_encode %{
|
|
||||||
__ ucomisd($src$$XMMRegister, $constantaddress($con));
|
|
||||||
emit_cmpfp_fixup(_masm);
|
|
||||||
%}
|
|
||||||
ins_pipe(pipe_slow);
|
|
||||||
%}
|
|
||||||
|
|
||||||
instruct cmpD_cc_immCF(rFlagsRegUCF cr, regD src, immD con) %{
|
instruct cmpD_cc_immCF(rFlagsRegUCF cr, regD src, immD con) %{
|
||||||
match(Set cr (CmpD src con));
|
match(Set cr (CmpD src con));
|
||||||
ins_cost(100);
|
ins_cost(100);
|
||||||
|
|
361
test/hotspot/jtreg/compiler/c2/irTests/TestFPComparison.java
Normal file
361
test/hotspot/jtreg/compiler/c2/irTests/TestFPComparison.java
Normal file
|
@ -0,0 +1,361 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 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
|
||||||
|
* 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 compiler.lib.ir_framework.*;
|
||||||
|
import jdk.test.lib.Asserts;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @bug 8285973
|
||||||
|
* @summary Test that code generation for fp comparison works as intended
|
||||||
|
* @library /test/lib /
|
||||||
|
* @run driver compiler.c2.irTests.TestFPComparison
|
||||||
|
*/
|
||||||
|
public class TestFPComparison {
|
||||||
|
static final double[] DOUBLES = new double[] {
|
||||||
|
Double.NEGATIVE_INFINITY,
|
||||||
|
-Double.MAX_VALUE,
|
||||||
|
-1.0,
|
||||||
|
-Double.MIN_VALUE,
|
||||||
|
-0.0,
|
||||||
|
0.0,
|
||||||
|
Double.MIN_VALUE,
|
||||||
|
1.0,
|
||||||
|
Double.MAX_VALUE,
|
||||||
|
Double.POSITIVE_INFINITY,
|
||||||
|
Double.NaN,
|
||||||
|
};
|
||||||
|
|
||||||
|
static final float[] FLOATS = new float[] {
|
||||||
|
Float.NEGATIVE_INFINITY,
|
||||||
|
-Float.MAX_VALUE,
|
||||||
|
-1.0F,
|
||||||
|
-Float.MIN_VALUE,
|
||||||
|
-0.0F,
|
||||||
|
0.0F,
|
||||||
|
Float.MIN_VALUE,
|
||||||
|
1.0F,
|
||||||
|
Float.MAX_VALUE,
|
||||||
|
Float.POSITIVE_INFINITY,
|
||||||
|
Float.NaN,
|
||||||
|
};
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
TestFramework.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
@DontInline
|
||||||
|
static int call() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IR(counts = {IRNode.CMOVEI, "1"})
|
||||||
|
public int cMoveEqualTwoDoubles(double x, double y) {
|
||||||
|
return x == y ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IR(counts = {IRNode.CMOVEI, "1"})
|
||||||
|
public int cMoveEqualTwoFloats(float x, float y) {
|
||||||
|
return x == y ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IR(counts = {IRNode.CMOVEI, "1"})
|
||||||
|
public int cMoveNotEqualTwoDoubles(double x, double y) {
|
||||||
|
return x != y ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IR(counts = {IRNode.CMOVEI, "1"})
|
||||||
|
public int cMoveNotEqualTwoFloats(float x, float y) {
|
||||||
|
return x != y ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IR(counts = {IRNode.CMOVEI, "1"})
|
||||||
|
public int cMoveLessThanTwoDoubles(double x, double y) {
|
||||||
|
return x < y ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IR(counts = {IRNode.CMOVEI, "1"})
|
||||||
|
public int cMoveLessThanTwoFloats(float x, float y) {
|
||||||
|
return x < y ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IR(counts = {IRNode.CMOVEI, "1"})
|
||||||
|
public int cMoveMoreThanTwoDoubles(double x, double y) {
|
||||||
|
return x > y ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IR(counts = {IRNode.CMOVEI, "1"})
|
||||||
|
public int cMoveMoreThanTwoFloats(float x, float y) {
|
||||||
|
return x > y ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IR(counts = {IRNode.CMOVEI, "1"})
|
||||||
|
public int cMoveLessEqualTwoDoubles(double x, double y) {
|
||||||
|
return x <= y ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IR(counts = {IRNode.CMOVEI, "1"})
|
||||||
|
public int cMoveLessEqualTwoFloats(float x, float y) {
|
||||||
|
return x <= y ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IR(counts = {IRNode.CMOVEI, "1"})
|
||||||
|
public int cMoveMoreEqualTwoDoubles(double x, double y) {
|
||||||
|
return x >= y ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IR(counts = {IRNode.CMOVEI, "1"})
|
||||||
|
public int cMoveMoreEqualTwoFloats(float x, float y) {
|
||||||
|
return x >= y ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IR(counts = {IRNode.CMOVEI, "1"})
|
||||||
|
public int cMoveEqualOneDouble(double x) {
|
||||||
|
return x == x ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IR(counts = {IRNode.CMOVEI, "1"})
|
||||||
|
public int cMoveEqualOneFloat(float x) {
|
||||||
|
return x == x ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IR(counts = {IRNode.CMOVEI, "1"})
|
||||||
|
public int cMoveNotEqualOneDouble(double x) {
|
||||||
|
return x != x ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IR(counts = {IRNode.CMOVEI, "1"})
|
||||||
|
public int cMoveNotEqualOneFloat(float x) {
|
||||||
|
return x != x ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IR(counts = {IRNode.IF, "1"})
|
||||||
|
public int branchEqualTwoDoubles(double x, double y) {
|
||||||
|
return x == y ? call() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IR(counts = {IRNode.IF, "1"})
|
||||||
|
public int branchEqualTwoFloats(float x, float y) {
|
||||||
|
return x == y ? call() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IR(counts = {IRNode.IF, "1"})
|
||||||
|
public int branchNotEqualTwoDoubles(double x, double y) {
|
||||||
|
return x != y ? call() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IR(counts = {IRNode.IF, "1"})
|
||||||
|
public int branchNotEqualTwoFloats(float x, float y) {
|
||||||
|
return x != y ? call() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IR(counts = {IRNode.IF, "1"})
|
||||||
|
public int branchLessThanTwoDoubles(double x, double y) {
|
||||||
|
return x < y ? call() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IR(counts = {IRNode.IF, "1"})
|
||||||
|
public int branchLessThanTwoFloats(float x, float y) {
|
||||||
|
return x < y ? call() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IR(counts = {IRNode.IF, "1"})
|
||||||
|
public int branchMoreThanTwoDoubles(double x, double y) {
|
||||||
|
return x > y ? call() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IR(counts = {IRNode.IF, "1"})
|
||||||
|
public int branchMoreThanTwoFloats(float x, float y) {
|
||||||
|
return x > y ? call() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IR(counts = {IRNode.IF, "1"})
|
||||||
|
public int branchLessEqualTwoDoubles(double x, double y) {
|
||||||
|
return x <= y ? call() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IR(counts = {IRNode.IF, "1"})
|
||||||
|
public int branchLessEqualTwoFloats(float x, float y) {
|
||||||
|
return x <= y ? call() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IR(counts = {IRNode.IF, "1"})
|
||||||
|
public int branchMoreEqualTwoDoubles(double x, double y) {
|
||||||
|
return x >= y ? call() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IR(counts = {IRNode.IF, "1"})
|
||||||
|
public int branchMoreEqualTwoFloats(float x, float y) {
|
||||||
|
return x >= y ? call() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IR(counts = {IRNode.IF, "1"})
|
||||||
|
public int branchEqualOneDouble(double x) {
|
||||||
|
return x == x ? call() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IR(counts = {IRNode.IF, "1"})
|
||||||
|
public int branchEqualOneFloat(float x) {
|
||||||
|
return x == x ? call() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IR(counts = {IRNode.IF, "1"})
|
||||||
|
public int branchNotEqualOneDouble(double x) {
|
||||||
|
return x != x ? call() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IR(counts = {IRNode.IF, "1"})
|
||||||
|
public int branchNotEqualOneFloat(float x) {
|
||||||
|
return x != x ? call() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Run(test = {"cMoveEqualTwoDoubles", "cMoveEqualTwoFloats", "cMoveNotEqualTwoDoubles", "cMoveNotEqualTwoFloats",
|
||||||
|
"cMoveLessThanTwoDoubles", "cMoveLessThanTwoFloats", "cMoveMoreThanTwoDoubles", "cMoveMoreThanTwoFloats",
|
||||||
|
"cMoveLessEqualTwoDoubles", "cMoveLessEqualTwoFloats", "cMoveMoreEqualTwoDoubles", "cMoveMoreEqualTwoFloats",
|
||||||
|
"cMoveEqualOneDouble", "cMoveEqualOneFloat", "cMoveNotEqualOneDouble", "cMoveNotEqualOneFloat",
|
||||||
|
"branchEqualTwoDoubles", "branchEqualTwoFloats", "branchNotEqualTwoDoubles", "branchNotEqualTwoFloats",
|
||||||
|
"branchLessThanTwoDoubles", "branchLessThanTwoFloats", "branchMoreThanTwoDoubles", "branchMoreThanTwoFloats",
|
||||||
|
"branchLessEqualTwoDoubles", "branchLessEqualTwoFloats", "branchMoreEqualTwoDoubles", "branchMoreEqualTwoFloats",
|
||||||
|
"branchEqualOneDouble", "branchEqualOneFloat", "branchNotEqualOneDouble", "branchNotEqualOneFloat"})
|
||||||
|
public void runTests() {
|
||||||
|
for (int i = 0; i < DOUBLES.length; i++) {
|
||||||
|
for (int j = 0; j < DOUBLES.length; j++) {
|
||||||
|
int len = DOUBLES.length;
|
||||||
|
double x = DOUBLES[i];
|
||||||
|
double y = DOUBLES[j];
|
||||||
|
Asserts.assertEquals(cMoveEqualTwoDoubles(x, x),
|
||||||
|
(x == x) ? 1 : 0);
|
||||||
|
Asserts.assertEquals(cMoveNotEqualTwoDoubles(x, x),
|
||||||
|
(x != x) ? 1 : 0);
|
||||||
|
Asserts.assertEquals(cMoveEqualTwoDoubles(x, y),
|
||||||
|
(x == y) ? 1 : 0);
|
||||||
|
Asserts.assertEquals(cMoveNotEqualTwoDoubles(x, y),
|
||||||
|
(x != y) ? 1 : 0);
|
||||||
|
Asserts.assertEquals(cMoveLessThanTwoDoubles(x, y),
|
||||||
|
(x < y) ? 1 : 0);
|
||||||
|
Asserts.assertEquals(cMoveLessEqualTwoDoubles(x, y),
|
||||||
|
(x <= y) ? 1 : 0);
|
||||||
|
Asserts.assertEquals(cMoveMoreThanTwoDoubles(x, y),
|
||||||
|
(x > y) ? 1 : 0);
|
||||||
|
Asserts.assertEquals(cMoveMoreEqualTwoDoubles(x, y),
|
||||||
|
(x >= y) ? 1 : 0);
|
||||||
|
Asserts.assertEquals(branchEqualTwoDoubles(x, y),
|
||||||
|
(x == y) ? 1 : 0);
|
||||||
|
Asserts.assertEquals(branchNotEqualTwoDoubles(x, y),
|
||||||
|
(x != y) ? 1 : 0);
|
||||||
|
Asserts.assertEquals(branchLessThanTwoDoubles(x, y),
|
||||||
|
(x < y) ? 1 : 0);
|
||||||
|
Asserts.assertEquals(branchLessEqualTwoDoubles(x, y),
|
||||||
|
(x <= y) ? 1 : 0);
|
||||||
|
Asserts.assertEquals(branchMoreThanTwoDoubles(x, y),
|
||||||
|
(x > y) ? 1 : 0);
|
||||||
|
Asserts.assertEquals(branchMoreEqualTwoDoubles(x, y),
|
||||||
|
(x >= y) ? 1 : 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0; i < FLOATS.length; i++) {
|
||||||
|
for (int j = 0; j < FLOATS.length; j++) {
|
||||||
|
int len = FLOATS.length;
|
||||||
|
float x = FLOATS[i];
|
||||||
|
float y = FLOATS[j];
|
||||||
|
Asserts.assertEquals(cMoveEqualTwoFloats(x, x),
|
||||||
|
(x == x) ? 1 : 0);
|
||||||
|
Asserts.assertEquals(cMoveNotEqualTwoFloats(x, x),
|
||||||
|
(x != x) ? 1 : 0);
|
||||||
|
Asserts.assertEquals(cMoveEqualTwoFloats(x, y),
|
||||||
|
(x == y) ? 1 : 0);
|
||||||
|
Asserts.assertEquals(cMoveNotEqualTwoFloats(x, y),
|
||||||
|
(x != y) ? 1 : 0);
|
||||||
|
Asserts.assertEquals(cMoveLessThanTwoFloats(x, y),
|
||||||
|
(x < y) ? 1 : 0);
|
||||||
|
Asserts.assertEquals(cMoveLessEqualTwoFloats(x, y),
|
||||||
|
(x <= y) ? 1 : 0);
|
||||||
|
Asserts.assertEquals(cMoveMoreThanTwoFloats(x, y),
|
||||||
|
(x > y) ? 1 : 0);
|
||||||
|
Asserts.assertEquals(cMoveMoreEqualTwoFloats(x, y),
|
||||||
|
(x >= y) ? 1 : 0);
|
||||||
|
Asserts.assertEquals(branchEqualTwoFloats(x, y),
|
||||||
|
(x == y) ? 1 : 0);
|
||||||
|
Asserts.assertEquals(branchNotEqualTwoFloats(x, y),
|
||||||
|
(x != y) ? 1 : 0);
|
||||||
|
Asserts.assertEquals(branchLessThanTwoFloats(x, y),
|
||||||
|
(x < y) ? 1 : 0);
|
||||||
|
Asserts.assertEquals(branchLessEqualTwoFloats(x, y),
|
||||||
|
(x <= y) ? 1 : 0);
|
||||||
|
Asserts.assertEquals(branchMoreThanTwoFloats(x, y),
|
||||||
|
(x > y) ? 1 : 0);
|
||||||
|
Asserts.assertEquals(branchMoreEqualTwoFloats(x, y),
|
||||||
|
(x >= y) ? 1 : 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0; i < DOUBLES.length; i++) {
|
||||||
|
Asserts.assertEquals(cMoveEqualOneDouble(DOUBLES[DOUBLES.length - 1]), 0);
|
||||||
|
Asserts.assertEquals(cMoveNotEqualOneDouble(DOUBLES[DOUBLES.length - 1]), 1);
|
||||||
|
Asserts.assertEquals(cMoveEqualOneDouble(DOUBLES[i]), (i != DOUBLES.length - 1) ? 1 : 0);
|
||||||
|
Asserts.assertEquals(cMoveNotEqualOneDouble(DOUBLES[i]), (i == DOUBLES.length - 1) ? 1 : 0);
|
||||||
|
Asserts.assertEquals(branchEqualOneDouble(DOUBLES[i]), (i != DOUBLES.length - 1) ? 1 : 0);
|
||||||
|
Asserts.assertEquals(branchNotEqualOneDouble(DOUBLES[i]), (i == DOUBLES.length - 1) ? 1 : 0);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < FLOATS.length; i++) {
|
||||||
|
Asserts.assertEquals(cMoveEqualOneFloat(FLOATS[FLOATS.length - 1]), 0);
|
||||||
|
Asserts.assertEquals(cMoveNotEqualOneFloat(FLOATS[FLOATS.length - 1]), 1);
|
||||||
|
Asserts.assertEquals(cMoveEqualOneFloat(FLOATS[i]), (i != FLOATS.length - 1) ? 1 : 0);
|
||||||
|
Asserts.assertEquals(cMoveNotEqualOneFloat(FLOATS[i]), (i == FLOATS.length - 1) ? 1 : 0);
|
||||||
|
Asserts.assertEquals(branchEqualOneFloat(FLOATS[i]), (i != FLOATS.length - 1) ? 1 : 0);
|
||||||
|
Asserts.assertEquals(branchNotEqualOneFloat(FLOATS[i]), (i == FLOATS.length - 1) ? 1 : 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -141,6 +141,7 @@ public class IRNode {
|
||||||
public static final String MEMBAR_STORESTORE = START + "MemBarStoreStore" + MID + END;
|
public static final String MEMBAR_STORESTORE = START + "MemBarStoreStore" + MID + END;
|
||||||
public static final String SAFEPOINT = START + "SafePoint" + MID + END;
|
public static final String SAFEPOINT = START + "SafePoint" + MID + END;
|
||||||
|
|
||||||
|
public static final String CMOVEI = START + "CMoveI" + MID + END;
|
||||||
public static final String ABS_I = START + "AbsI" + 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_L = START + "AbsL" + MID + END;
|
||||||
public static final String ABS_F = START + "AbsF" + MID + END;
|
public static final String ABS_F = START + "AbsF" + MID + END;
|
||||||
|
|
132
test/micro/org/openjdk/bench/java/lang/FPComparison.java
Normal file
132
test/micro/org/openjdk/bench/java/lang/FPComparison.java
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 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
|
||||||
|
* 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.lang;
|
||||||
|
|
||||||
|
import org.openjdk.jmh.annotations.*;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.random.RandomGenerator;
|
||||||
|
|
||||||
|
@BenchmarkMode(Mode.AverageTime)
|
||||||
|
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
||||||
|
@State(Scope.Thread)
|
||||||
|
@Fork(1)
|
||||||
|
public class FPComparison {
|
||||||
|
static final int INVOCATIONS = 1024;
|
||||||
|
|
||||||
|
float[] f1;
|
||||||
|
double[] d1;
|
||||||
|
float[] f2;
|
||||||
|
double[] d2;
|
||||||
|
int[] res;
|
||||||
|
|
||||||
|
@Setup
|
||||||
|
public void setup() {
|
||||||
|
var random = RandomGenerator.getDefault();
|
||||||
|
f1 = new float[INVOCATIONS];
|
||||||
|
d1 = new double[INVOCATIONS];
|
||||||
|
f2 = new float[INVOCATIONS];
|
||||||
|
d2 = new double[INVOCATIONS];
|
||||||
|
res = new int[INVOCATIONS];
|
||||||
|
for (int i = 0; i < INVOCATIONS; i++) {
|
||||||
|
int type = random.nextInt(5);
|
||||||
|
if (type == 1) {
|
||||||
|
f1[i] = random.nextFloat();
|
||||||
|
d1[i] = random.nextDouble();
|
||||||
|
f2[i] = random.nextFloat();
|
||||||
|
d2[i] = random.nextDouble();
|
||||||
|
} else if (type == 2) {
|
||||||
|
f1[i] = Float.POSITIVE_INFINITY;
|
||||||
|
d1[i] = Double.POSITIVE_INFINITY;
|
||||||
|
f2[i] = Float.POSITIVE_INFINITY;
|
||||||
|
d2[i] = Double.POSITIVE_INFINITY;
|
||||||
|
} else if (type == 3) {
|
||||||
|
f1[i] = Float.NEGATIVE_INFINITY;
|
||||||
|
d1[i] = Double.NEGATIVE_INFINITY;
|
||||||
|
f2[i] = Float.NEGATIVE_INFINITY;
|
||||||
|
d2[i] = Double.NEGATIVE_INFINITY;
|
||||||
|
} else if (type >= 4) {
|
||||||
|
f1[i] = Float.NaN;
|
||||||
|
d1[i] = Double.NaN;
|
||||||
|
f2[i] = Float.NaN;
|
||||||
|
d2[i] = Double.NaN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public void isNanFloat() {
|
||||||
|
for (int i = 0; i < INVOCATIONS; i++) {
|
||||||
|
res[i] = Float.isNaN(f1[i]) ? 1 : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public void isNanDouble() {
|
||||||
|
for (int i = 0; i < INVOCATIONS; i++) {
|
||||||
|
res[i] = Double.isNaN(d1[i]) ? 1 : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public void isInfiniteFloat() {
|
||||||
|
for (int i = 0; i < INVOCATIONS; i++) {
|
||||||
|
res[i] = Float.isInfinite(f1[i]) ? 1 : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public void isInfiniteDouble() {
|
||||||
|
for (int i = 0; i < INVOCATIONS; i++) {
|
||||||
|
res[i] = Double.isInfinite(d1[i]) ? 1 : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public void isFiniteFloat() {
|
||||||
|
for (int i = 0; i < INVOCATIONS; i++) {
|
||||||
|
res[i] = Float.isFinite(f1[i]) ? 1 : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public void isFiniteDouble() {
|
||||||
|
for (int i = 0; i < INVOCATIONS; i++) {
|
||||||
|
res[i] = Double.isFinite(d1[i]) ? 1 : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public void equalFloat() {
|
||||||
|
for (int i = 0; i < INVOCATIONS; i++) {
|
||||||
|
res[i] = (f1[i] == f2[i]) ? 1 : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public void equalDouble() {
|
||||||
|
for (int i = 0; i < INVOCATIONS; i++) {
|
||||||
|
res[i] = (d1[i] == d2[i]) ? 1 : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue