8282221: x86 intrinsics for divideUnsigned and remainderUnsigned methods in java.lang.Integer and java.lang.Long
Reviewed-by: sviswanathan, kvn, jbhateja
This commit is contained in:
parent
0b867b5e73
commit
37e28aea27
@ -12366,6 +12366,11 @@ void Assembler::idivq(Register src) {
|
|||||||
emit_int16((unsigned char)0xF7, (0xF8 | encode));
|
emit_int16((unsigned char)0xF7, (0xF8 | encode));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Assembler::divq(Register src) {
|
||||||
|
int encode = prefixq_and_encode(src->encoding());
|
||||||
|
emit_int16((unsigned char)0xF7, (0xF0 | encode));
|
||||||
|
}
|
||||||
|
|
||||||
void Assembler::imulq(Register dst, Register src) {
|
void Assembler::imulq(Register dst, Register src) {
|
||||||
int encode = prefixq_and_encode(dst->encoding(), src->encoding());
|
int encode = prefixq_and_encode(dst->encoding(), src->encoding());
|
||||||
emit_int24(0x0F, (unsigned char)0xAF, (0xC0 | encode));
|
emit_int24(0x0F, (unsigned char)0xAF, (0xC0 | encode));
|
||||||
|
@ -1368,6 +1368,7 @@ private:
|
|||||||
|
|
||||||
#ifdef _LP64
|
#ifdef _LP64
|
||||||
void idivq(Register src);
|
void idivq(Register src);
|
||||||
|
void divq(Register src); // Unsigned division
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void imull(Register src);
|
void imull(Register src);
|
||||||
|
@ -4534,3 +4534,167 @@ void C2_MacroAssembler::vector_maskall_operation32(KRegister dst, Register src,
|
|||||||
kunpckdql(dst, tmp, tmp);
|
kunpckdql(dst, tmp, tmp);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void C2_MacroAssembler::udivI(Register rax, Register divisor, Register rdx) {
|
||||||
|
Label done;
|
||||||
|
Label neg_divisor_fastpath;
|
||||||
|
cmpl(divisor, 0);
|
||||||
|
jccb(Assembler::less, neg_divisor_fastpath);
|
||||||
|
xorl(rdx, rdx);
|
||||||
|
divl(divisor);
|
||||||
|
jmpb(done);
|
||||||
|
bind(neg_divisor_fastpath);
|
||||||
|
// Fastpath for divisor < 0:
|
||||||
|
// quotient = (dividend & ~(dividend - divisor)) >>> (Integer.SIZE - 1)
|
||||||
|
// See Hacker's Delight (2nd ed), section 9.3 which is implemented in java.lang.Long.divideUnsigned()
|
||||||
|
movl(rdx, rax);
|
||||||
|
subl(rdx, divisor);
|
||||||
|
if (VM_Version::supports_bmi1()) {
|
||||||
|
andnl(rax, rdx, rax);
|
||||||
|
} else {
|
||||||
|
notl(rdx);
|
||||||
|
andl(rax, rdx);
|
||||||
|
}
|
||||||
|
shrl(rax, 31);
|
||||||
|
bind(done);
|
||||||
|
}
|
||||||
|
|
||||||
|
void C2_MacroAssembler::umodI(Register rax, Register divisor, Register rdx) {
|
||||||
|
Label done;
|
||||||
|
Label neg_divisor_fastpath;
|
||||||
|
cmpl(divisor, 0);
|
||||||
|
jccb(Assembler::less, neg_divisor_fastpath);
|
||||||
|
xorl(rdx, rdx);
|
||||||
|
divl(divisor);
|
||||||
|
jmpb(done);
|
||||||
|
bind(neg_divisor_fastpath);
|
||||||
|
// Fastpath when divisor < 0:
|
||||||
|
// remainder = dividend - (((dividend & ~(dividend - divisor)) >> (Integer.SIZE - 1)) & divisor)
|
||||||
|
// See Hacker's Delight (2nd ed), section 9.3 which is implemented in java.lang.Long.remainderUnsigned()
|
||||||
|
movl(rdx, rax);
|
||||||
|
subl(rax, divisor);
|
||||||
|
if (VM_Version::supports_bmi1()) {
|
||||||
|
andnl(rax, rax, rdx);
|
||||||
|
} else {
|
||||||
|
notl(rax);
|
||||||
|
andl(rax, rdx);
|
||||||
|
}
|
||||||
|
sarl(rax, 31);
|
||||||
|
andl(rax, divisor);
|
||||||
|
subl(rdx, rax);
|
||||||
|
bind(done);
|
||||||
|
}
|
||||||
|
|
||||||
|
void C2_MacroAssembler::udivmodI(Register rax, Register divisor, Register rdx, Register tmp) {
|
||||||
|
Label done;
|
||||||
|
Label neg_divisor_fastpath;
|
||||||
|
|
||||||
|
cmpl(divisor, 0);
|
||||||
|
jccb(Assembler::less, neg_divisor_fastpath);
|
||||||
|
xorl(rdx, rdx);
|
||||||
|
divl(divisor);
|
||||||
|
jmpb(done);
|
||||||
|
bind(neg_divisor_fastpath);
|
||||||
|
// Fastpath for divisor < 0:
|
||||||
|
// quotient = (dividend & ~(dividend - divisor)) >>> (Integer.SIZE - 1)
|
||||||
|
// remainder = dividend - (((dividend & ~(dividend - divisor)) >> (Integer.SIZE - 1)) & divisor)
|
||||||
|
// See Hacker's Delight (2nd ed), section 9.3 which is implemented in
|
||||||
|
// java.lang.Long.divideUnsigned() and java.lang.Long.remainderUnsigned()
|
||||||
|
movl(rdx, rax);
|
||||||
|
subl(rax, divisor);
|
||||||
|
if (VM_Version::supports_bmi1()) {
|
||||||
|
andnl(rax, rax, rdx);
|
||||||
|
} else {
|
||||||
|
notl(rax);
|
||||||
|
andl(rax, rdx);
|
||||||
|
}
|
||||||
|
movl(tmp, rax);
|
||||||
|
shrl(rax, 31); // quotient
|
||||||
|
sarl(tmp, 31);
|
||||||
|
andl(tmp, divisor);
|
||||||
|
subl(rdx, tmp); // remainder
|
||||||
|
bind(done);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _LP64
|
||||||
|
void C2_MacroAssembler::udivL(Register rax, Register divisor, Register rdx) {
|
||||||
|
Label done;
|
||||||
|
Label neg_divisor_fastpath;
|
||||||
|
cmpq(divisor, 0);
|
||||||
|
jccb(Assembler::less, neg_divisor_fastpath);
|
||||||
|
xorl(rdx, rdx);
|
||||||
|
divq(divisor);
|
||||||
|
jmpb(done);
|
||||||
|
bind(neg_divisor_fastpath);
|
||||||
|
// Fastpath for divisor < 0:
|
||||||
|
// quotient = (dividend & ~(dividend - divisor)) >>> (Long.SIZE - 1)
|
||||||
|
// See Hacker's Delight (2nd ed), section 9.3 which is implemented in java.lang.Long.divideUnsigned()
|
||||||
|
movq(rdx, rax);
|
||||||
|
subq(rdx, divisor);
|
||||||
|
if (VM_Version::supports_bmi1()) {
|
||||||
|
andnq(rax, rdx, rax);
|
||||||
|
} else {
|
||||||
|
notq(rdx);
|
||||||
|
andq(rax, rdx);
|
||||||
|
}
|
||||||
|
shrq(rax, 63);
|
||||||
|
bind(done);
|
||||||
|
}
|
||||||
|
|
||||||
|
void C2_MacroAssembler::umodL(Register rax, Register divisor, Register rdx) {
|
||||||
|
Label done;
|
||||||
|
Label neg_divisor_fastpath;
|
||||||
|
cmpq(divisor, 0);
|
||||||
|
jccb(Assembler::less, neg_divisor_fastpath);
|
||||||
|
xorq(rdx, rdx);
|
||||||
|
divq(divisor);
|
||||||
|
jmp(done);
|
||||||
|
bind(neg_divisor_fastpath);
|
||||||
|
// Fastpath when divisor < 0:
|
||||||
|
// remainder = dividend - (((dividend & ~(dividend - divisor)) >> (Long.SIZE - 1)) & divisor)
|
||||||
|
// See Hacker's Delight (2nd ed), section 9.3 which is implemented in java.lang.Long.remainderUnsigned()
|
||||||
|
movq(rdx, rax);
|
||||||
|
subq(rax, divisor);
|
||||||
|
if (VM_Version::supports_bmi1()) {
|
||||||
|
andnq(rax, rax, rdx);
|
||||||
|
} else {
|
||||||
|
notq(rax);
|
||||||
|
andq(rax, rdx);
|
||||||
|
}
|
||||||
|
sarq(rax, 63);
|
||||||
|
andq(rax, divisor);
|
||||||
|
subq(rdx, rax);
|
||||||
|
bind(done);
|
||||||
|
}
|
||||||
|
|
||||||
|
void C2_MacroAssembler::udivmodL(Register rax, Register divisor, Register rdx, Register tmp) {
|
||||||
|
Label done;
|
||||||
|
Label neg_divisor_fastpath;
|
||||||
|
cmpq(divisor, 0);
|
||||||
|
jccb(Assembler::less, neg_divisor_fastpath);
|
||||||
|
xorq(rdx, rdx);
|
||||||
|
divq(divisor);
|
||||||
|
jmp(done);
|
||||||
|
bind(neg_divisor_fastpath);
|
||||||
|
// Fastpath for divisor < 0:
|
||||||
|
// quotient = (dividend & ~(dividend - divisor)) >>> (Long.SIZE - 1)
|
||||||
|
// remainder = dividend - (((dividend & ~(dividend - divisor)) >> (Long.SIZE - 1)) & divisor)
|
||||||
|
// See Hacker's Delight (2nd ed), section 9.3 which is implemented in
|
||||||
|
// java.lang.Long.divideUnsigned() and java.lang.Long.remainderUnsigned()
|
||||||
|
movq(rdx, rax);
|
||||||
|
subq(rax, divisor);
|
||||||
|
if (VM_Version::supports_bmi1()) {
|
||||||
|
andnq(rax, rax, rdx);
|
||||||
|
} else {
|
||||||
|
notq(rax);
|
||||||
|
andq(rax, rdx);
|
||||||
|
}
|
||||||
|
movq(tmp, rax);
|
||||||
|
shrq(rax, 63); // quotient
|
||||||
|
sarq(tmp, 63);
|
||||||
|
andq(tmp, divisor);
|
||||||
|
subq(rdx, tmp); // remainder
|
||||||
|
bind(done);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
@ -340,6 +340,15 @@ public:
|
|||||||
void evpternlog(XMMRegister dst, int func, KRegister mask, XMMRegister src2, Address src3,
|
void evpternlog(XMMRegister dst, int func, KRegister mask, XMMRegister src2, Address src3,
|
||||||
bool merge, BasicType bt, int vlen_enc);
|
bool merge, BasicType bt, int vlen_enc);
|
||||||
|
|
||||||
|
void udivI(Register rax, Register divisor, Register rdx);
|
||||||
|
void umodI(Register rax, Register divisor, Register rdx);
|
||||||
|
void udivmodI(Register rax, Register divisor, Register rdx, Register tmp);
|
||||||
|
|
||||||
|
#ifdef _LP64
|
||||||
|
void udivL(Register rax, Register divisor, Register rdx);
|
||||||
|
void umodL(Register rax, Register divisor, Register rdx);
|
||||||
|
void udivmodL(Register rax, Register divisor, Register rdx, Register tmp);
|
||||||
|
#endif
|
||||||
void vector_popcount_int(XMMRegister dst, XMMRegister src, XMMRegister xtmp1,
|
void vector_popcount_int(XMMRegister dst, XMMRegister src, XMMRegister xtmp1,
|
||||||
XMMRegister xtmp2, XMMRegister xtmp3, Register rtmp,
|
XMMRegister xtmp2, XMMRegister xtmp3, Register rtmp,
|
||||||
int vec_enc);
|
int vec_enc);
|
||||||
|
@ -8688,6 +8688,32 @@ instruct divL_rReg(rax_RegL rax, rdx_RegL rdx, no_rax_rdx_RegL div,
|
|||||||
ins_pipe(ialu_reg_reg_alu0);
|
ins_pipe(ialu_reg_reg_alu0);
|
||||||
%}
|
%}
|
||||||
|
|
||||||
|
instruct udivI_rReg(rax_RegI rax, rdx_RegI rdx, no_rax_rdx_RegI div, rFlagsReg cr)
|
||||||
|
%{
|
||||||
|
match(Set rax (UDivI rax div));
|
||||||
|
effect(KILL rdx, KILL cr);
|
||||||
|
|
||||||
|
ins_cost(300);
|
||||||
|
format %{ "udivl $rax,$rax,$div\t# UDivI\n" %}
|
||||||
|
ins_encode %{
|
||||||
|
__ udivI($rax$$Register, $div$$Register, $rdx$$Register);
|
||||||
|
%}
|
||||||
|
ins_pipe(ialu_reg_reg_alu0);
|
||||||
|
%}
|
||||||
|
|
||||||
|
instruct udivL_rReg(rax_RegL rax, rdx_RegL rdx, no_rax_rdx_RegL div, rFlagsReg cr)
|
||||||
|
%{
|
||||||
|
match(Set rax (UDivL rax div));
|
||||||
|
effect(KILL rdx, KILL cr);
|
||||||
|
|
||||||
|
ins_cost(300);
|
||||||
|
format %{ "udivq $rax,$rax,$div\t# UDivL\n" %}
|
||||||
|
ins_encode %{
|
||||||
|
__ udivL($rax$$Register, $div$$Register, $rdx$$Register);
|
||||||
|
%}
|
||||||
|
ins_pipe(ialu_reg_reg_alu0);
|
||||||
|
%}
|
||||||
|
|
||||||
// Integer DIVMOD with Register, both quotient and mod results
|
// Integer DIVMOD with Register, both quotient and mod results
|
||||||
instruct divModI_rReg_divmod(rax_RegI rax, rdx_RegI rdx, no_rax_rdx_RegI div,
|
instruct divModI_rReg_divmod(rax_RegI rax, rdx_RegI rdx, no_rax_rdx_RegI div,
|
||||||
rFlagsReg cr)
|
rFlagsReg cr)
|
||||||
@ -8729,6 +8755,41 @@ instruct divModL_rReg_divmod(rax_RegL rax, rdx_RegL rdx, no_rax_rdx_RegL div,
|
|||||||
ins_pipe(pipe_slow);
|
ins_pipe(pipe_slow);
|
||||||
%}
|
%}
|
||||||
|
|
||||||
|
// Unsigned integer DIVMOD with Register, both quotient and mod results
|
||||||
|
instruct udivModI_rReg_divmod(rax_RegI rax, no_rax_rdx_RegI tmp, rdx_RegI rdx,
|
||||||
|
no_rax_rdx_RegI div, rFlagsReg cr)
|
||||||
|
%{
|
||||||
|
match(UDivModI rax div);
|
||||||
|
effect(TEMP tmp, KILL cr);
|
||||||
|
|
||||||
|
ins_cost(300);
|
||||||
|
format %{ "udivl $rax,$rax,$div\t# begin UDivModI\n\t"
|
||||||
|
"umodl $rdx,$rax,$div\t! using $tmp as TEMP # end UDivModI\n"
|
||||||
|
%}
|
||||||
|
ins_encode %{
|
||||||
|
__ udivmodI($rax$$Register, $div$$Register, $rdx$$Register, $tmp$$Register);
|
||||||
|
%}
|
||||||
|
ins_pipe(pipe_slow);
|
||||||
|
%}
|
||||||
|
|
||||||
|
// Unsigned long DIVMOD with Register, both quotient and mod results
|
||||||
|
instruct udivModL_rReg_divmod(rax_RegL rax, no_rax_rdx_RegL tmp, rdx_RegL rdx,
|
||||||
|
no_rax_rdx_RegL div, rFlagsReg cr)
|
||||||
|
%{
|
||||||
|
match(UDivModL rax div);
|
||||||
|
effect(TEMP tmp, KILL cr);
|
||||||
|
|
||||||
|
ins_cost(300);
|
||||||
|
format %{ "udivq $rax,$rax,$div\t# begin UDivModL\n\t"
|
||||||
|
"umodq $rdx,$rax,$div\t! using $tmp as TEMP # end UDivModL\n"
|
||||||
|
%}
|
||||||
|
ins_encode %{
|
||||||
|
__ udivmodL($rax$$Register, $div$$Register, $rdx$$Register, $tmp$$Register);
|
||||||
|
%}
|
||||||
|
ins_pipe(pipe_slow);
|
||||||
|
%}
|
||||||
|
|
||||||
|
|
||||||
//----------- DivL-By-Constant-Expansions--------------------------------------
|
//----------- DivL-By-Constant-Expansions--------------------------------------
|
||||||
// DivI cases are handled by the compiler
|
// DivI cases are handled by the compiler
|
||||||
|
|
||||||
@ -8832,6 +8893,32 @@ instruct modL_rReg(rdx_RegL rdx, rax_RegL rax, no_rax_rdx_RegL div,
|
|||||||
ins_pipe(ialu_reg_reg_alu0);
|
ins_pipe(ialu_reg_reg_alu0);
|
||||||
%}
|
%}
|
||||||
|
|
||||||
|
instruct umodI_rReg(rdx_RegI rdx, rax_RegI rax, no_rax_rdx_RegI div, rFlagsReg cr)
|
||||||
|
%{
|
||||||
|
match(Set rdx (UModI rax div));
|
||||||
|
effect(KILL rax, KILL cr);
|
||||||
|
|
||||||
|
ins_cost(300);
|
||||||
|
format %{ "umodl $rdx,$rax,$div\t# UModI\n" %}
|
||||||
|
ins_encode %{
|
||||||
|
__ umodI($rax$$Register, $div$$Register, $rdx$$Register);
|
||||||
|
%}
|
||||||
|
ins_pipe(ialu_reg_reg_alu0);
|
||||||
|
%}
|
||||||
|
|
||||||
|
instruct umodL_rReg(rdx_RegL rdx, rax_RegL rax, no_rax_rdx_RegL div, rFlagsReg cr)
|
||||||
|
%{
|
||||||
|
match(Set rdx (UModL rax div));
|
||||||
|
effect(KILL rax, KILL cr);
|
||||||
|
|
||||||
|
ins_cost(300);
|
||||||
|
format %{ "umodq $rdx,$rax,$div\t# UModL\n" %}
|
||||||
|
ins_encode %{
|
||||||
|
__ umodL($rax$$Register, $div$$Register, $rdx$$Register);
|
||||||
|
%}
|
||||||
|
ins_pipe(ialu_reg_reg_alu0);
|
||||||
|
%}
|
||||||
|
|
||||||
// Integer Shift Instructions
|
// Integer Shift Instructions
|
||||||
// Shift Left by one
|
// Shift Left by one
|
||||||
instruct salI_rReg_1(rRegI dst, immI_1 shift, rFlagsReg cr)
|
instruct salI_rReg_1(rRegI dst, immI_1 shift, rFlagsReg cr)
|
||||||
|
@ -216,6 +216,12 @@ class methodHandle;
|
|||||||
do_intrinsic(_longBitsToDouble, java_lang_Double, longBitsToDouble_name, long_double_signature, F_SN)\
|
do_intrinsic(_longBitsToDouble, java_lang_Double, longBitsToDouble_name, long_double_signature, F_SN)\
|
||||||
do_name( longBitsToDouble_name, "longBitsToDouble") \
|
do_name( longBitsToDouble_name, "longBitsToDouble") \
|
||||||
\
|
\
|
||||||
|
do_intrinsic(_divideUnsigned_i, java_lang_Integer, divideUnsigned_name, int2_int_signature, F_S) \
|
||||||
|
do_intrinsic(_remainderUnsigned_i, java_lang_Integer, remainderUnsigned_name, int2_int_signature, F_S) \
|
||||||
|
do_name( divideUnsigned_name, "divideUnsigned") \
|
||||||
|
do_intrinsic(_divideUnsigned_l, java_lang_Long, divideUnsigned_name, long2_long_signature, F_S) \
|
||||||
|
do_intrinsic(_remainderUnsigned_l, java_lang_Long, remainderUnsigned_name, long2_long_signature, F_S) \
|
||||||
|
do_name( remainderUnsigned_name, "remainderUnsigned") \
|
||||||
do_intrinsic(_numberOfLeadingZeros_i, java_lang_Integer, numberOfLeadingZeros_name,int_int_signature, F_S) \
|
do_intrinsic(_numberOfLeadingZeros_i, java_lang_Integer, numberOfLeadingZeros_name,int_int_signature, F_S) \
|
||||||
do_intrinsic(_numberOfLeadingZeros_l, java_lang_Long, numberOfLeadingZeros_name,long_int_signature, F_S) \
|
do_intrinsic(_numberOfLeadingZeros_l, java_lang_Long, numberOfLeadingZeros_name,long_int_signature, F_S) \
|
||||||
\
|
\
|
||||||
|
@ -267,6 +267,18 @@ bool C2Compiler::is_intrinsic_supported(const methodHandle& method, bool is_virt
|
|||||||
case vmIntrinsics::_reverseBytes_l:
|
case vmIntrinsics::_reverseBytes_l:
|
||||||
if (!Matcher::match_rule_supported(Op_ReverseBytesL)) return false;
|
if (!Matcher::match_rule_supported(Op_ReverseBytesL)) return false;
|
||||||
break;
|
break;
|
||||||
|
case vmIntrinsics::_divideUnsigned_i:
|
||||||
|
if (!Matcher::match_rule_supported(Op_UDivI)) return false;
|
||||||
|
break;
|
||||||
|
case vmIntrinsics::_remainderUnsigned_i:
|
||||||
|
if (!Matcher::match_rule_supported(Op_UModI)) return false;
|
||||||
|
break;
|
||||||
|
case vmIntrinsics::_divideUnsigned_l:
|
||||||
|
if (!Matcher::match_rule_supported(Op_UDivL)) return false;
|
||||||
|
break;
|
||||||
|
case vmIntrinsics::_remainderUnsigned_l:
|
||||||
|
if (!Matcher::match_rule_supported(Op_UModL)) return false;
|
||||||
|
break;
|
||||||
|
|
||||||
/* CompareAndSet, Object: */
|
/* CompareAndSet, Object: */
|
||||||
case vmIntrinsics::_compareAndSetReference:
|
case vmIntrinsics::_compareAndSetReference:
|
||||||
|
@ -162,9 +162,13 @@ macro(DivD)
|
|||||||
macro(DivF)
|
macro(DivF)
|
||||||
macro(DivI)
|
macro(DivI)
|
||||||
macro(DivL)
|
macro(DivL)
|
||||||
|
macro(UDivI)
|
||||||
|
macro(UDivL)
|
||||||
macro(DivMod)
|
macro(DivMod)
|
||||||
macro(DivModI)
|
macro(DivModI)
|
||||||
macro(DivModL)
|
macro(DivModL)
|
||||||
|
macro(UDivModI)
|
||||||
|
macro(UDivModL)
|
||||||
macro(EncodeISOArray)
|
macro(EncodeISOArray)
|
||||||
macro(EncodeP)
|
macro(EncodeP)
|
||||||
macro(EncodePKlass)
|
macro(EncodePKlass)
|
||||||
@ -231,6 +235,8 @@ macro(ModD)
|
|||||||
macro(ModF)
|
macro(ModF)
|
||||||
macro(ModI)
|
macro(ModI)
|
||||||
macro(ModL)
|
macro(ModL)
|
||||||
|
macro(UModI)
|
||||||
|
macro(UModL)
|
||||||
macro(MoveI2F)
|
macro(MoveI2F)
|
||||||
macro(MoveF2I)
|
macro(MoveF2I)
|
||||||
macro(MoveL2D)
|
macro(MoveL2D)
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
* questions.
|
* questions.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "jvm_io.h"
|
#include "jvm_io.h"
|
||||||
#include "asm/macroAssembler.hpp"
|
#include "asm/macroAssembler.hpp"
|
||||||
@ -3500,6 +3499,36 @@ void Compile::final_graph_reshaping_main_switch(Node* n, Final_Reshape_Counts& f
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Op_UModI:
|
||||||
|
if (UseDivMod) {
|
||||||
|
// Check if a%b and a/b both exist
|
||||||
|
Node* d = n->find_similar(Op_UDivI);
|
||||||
|
if (d) {
|
||||||
|
// Replace them with a fused unsigned divmod if supported
|
||||||
|
if (Matcher::has_match_rule(Op_UDivModI)) {
|
||||||
|
UDivModINode* divmod = UDivModINode::make(n);
|
||||||
|
d->subsume_by(divmod->div_proj(), this);
|
||||||
|
n->subsume_by(divmod->mod_proj(), this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Op_UModL:
|
||||||
|
if (UseDivMod) {
|
||||||
|
// Check if a%b and a/b both exist
|
||||||
|
Node* d = n->find_similar(Op_UDivL);
|
||||||
|
if (d) {
|
||||||
|
// Replace them with a fused unsigned divmod if supported
|
||||||
|
if (Matcher::has_match_rule(Op_UDivModL)) {
|
||||||
|
UDivModLNode* divmod = UDivModLNode::make(n);
|
||||||
|
d->subsume_by(divmod->div_proj(), this);
|
||||||
|
n->subsume_by(divmod->mod_proj(), this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case Op_LoadVector:
|
case Op_LoadVector:
|
||||||
case Op_StoreVector:
|
case Op_StoreVector:
|
||||||
case Op_LoadVectorGather:
|
case Op_LoadVectorGather:
|
||||||
|
@ -841,6 +841,84 @@ Node *DivDNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
|||||||
return (new MulDNode(in(1), phase->makecon(TypeD::make(reciprocal))));
|
return (new MulDNode(in(1), phase->makecon(TypeD::make(reciprocal))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//------------------------------Identity---------------------------------------
|
||||||
|
// If the divisor is 1, we are an identity on the dividend.
|
||||||
|
Node* UDivINode::Identity(PhaseGVN* phase) {
|
||||||
|
return (phase->type( in(2) )->higher_equal(TypeInt::ONE)) ? in(1) : this;
|
||||||
|
}
|
||||||
|
//------------------------------Value------------------------------------------
|
||||||
|
// A UDivINode divides its inputs. The third input is a Control input, used to
|
||||||
|
// prevent hoisting the divide above an unsafe test.
|
||||||
|
const Type* UDivINode::Value(PhaseGVN* phase) const {
|
||||||
|
// Either input is TOP ==> the result is TOP
|
||||||
|
const Type *t1 = phase->type( in(1) );
|
||||||
|
const Type *t2 = phase->type( in(2) );
|
||||||
|
if( t1 == Type::TOP ) return Type::TOP;
|
||||||
|
if( t2 == Type::TOP ) return Type::TOP;
|
||||||
|
|
||||||
|
// x/x == 1 since we always generate the dynamic divisor check for 0.
|
||||||
|
if (in(1) == in(2)) {
|
||||||
|
return TypeInt::ONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Either input is BOTTOM ==> the result is the local BOTTOM
|
||||||
|
const Type *bot = bottom_type();
|
||||||
|
if( (t1 == bot) || (t2 == bot) ||
|
||||||
|
(t1 == Type::BOTTOM) || (t2 == Type::BOTTOM) )
|
||||||
|
return bot;
|
||||||
|
|
||||||
|
// Otherwise we give up all hope
|
||||||
|
return TypeInt::INT;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------Idealize---------------------------------------
|
||||||
|
Node *UDivINode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||||
|
// Check for dead control input
|
||||||
|
if (in(0) && remove_dead_region(phase, can_reshape)) return this;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//------------------------------Identity---------------------------------------
|
||||||
|
// If the divisor is 1, we are an identity on the dividend.
|
||||||
|
Node* UDivLNode::Identity(PhaseGVN* phase) {
|
||||||
|
return (phase->type( in(2) )->higher_equal(TypeLong::ONE)) ? in(1) : this;
|
||||||
|
}
|
||||||
|
//------------------------------Value------------------------------------------
|
||||||
|
// A UDivLNode divides its inputs. The third input is a Control input, used to
|
||||||
|
// prevent hoisting the divide above an unsafe test.
|
||||||
|
const Type* UDivLNode::Value(PhaseGVN* phase) const {
|
||||||
|
// Either input is TOP ==> the result is TOP
|
||||||
|
const Type *t1 = phase->type( in(1) );
|
||||||
|
const Type *t2 = phase->type( in(2) );
|
||||||
|
if( t1 == Type::TOP ) return Type::TOP;
|
||||||
|
if( t2 == Type::TOP ) return Type::TOP;
|
||||||
|
|
||||||
|
// x/x == 1 since we always generate the dynamic divisor check for 0.
|
||||||
|
if (in(1) == in(2)) {
|
||||||
|
return TypeLong::ONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Either input is BOTTOM ==> the result is the local BOTTOM
|
||||||
|
const Type *bot = bottom_type();
|
||||||
|
if( (t1 == bot) || (t2 == bot) ||
|
||||||
|
(t1 == Type::BOTTOM) || (t2 == Type::BOTTOM) )
|
||||||
|
return bot;
|
||||||
|
|
||||||
|
// Otherwise we give up all hope
|
||||||
|
return TypeLong::LONG;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------Idealize---------------------------------------
|
||||||
|
Node *UDivLNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||||
|
// Check for dead control input
|
||||||
|
if (in(0) && remove_dead_region(phase, can_reshape)) return this;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
//------------------------------Idealize---------------------------------------
|
//------------------------------Idealize---------------------------------------
|
||||||
Node *ModINode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
Node *ModINode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||||
@ -1005,6 +1083,13 @@ const Type* ModINode::Value(PhaseGVN* phase) const {
|
|||||||
return TypeInt::make( i1->get_con() % i2->get_con() );
|
return TypeInt::make( i1->get_con() % i2->get_con() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//------------------------------Idealize---------------------------------------
|
||||||
|
Node *UModINode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||||
|
// Check for dead control input
|
||||||
|
if( in(0) && remove_dead_region(phase, can_reshape) ) return this;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
//------------------------------Idealize---------------------------------------
|
//------------------------------Idealize---------------------------------------
|
||||||
@ -1216,6 +1301,14 @@ const Type* ModFNode::Value(PhaseGVN* phase) const {
|
|||||||
return TypeF::make(jfloat_cast(xr));
|
return TypeF::make(jfloat_cast(xr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//------------------------------Idealize---------------------------------------
|
||||||
|
Node *UModLNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||||
|
// Check for dead control input
|
||||||
|
if( in(0) && remove_dead_region(phase, can_reshape) ) return this;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
//------------------------------Value------------------------------------------
|
//------------------------------Value------------------------------------------
|
||||||
@ -1320,3 +1413,56 @@ Node *DivModLNode::match( const ProjNode *proj, const Matcher *match ) {
|
|||||||
}
|
}
|
||||||
return new MachProjNode(this, proj->_con, rm, ideal_reg);
|
return new MachProjNode(this, proj->_con, rm, ideal_reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//------------------------------make------------------------------------------
|
||||||
|
UDivModINode* UDivModINode::make(Node* div_or_mod) {
|
||||||
|
Node* n = div_or_mod;
|
||||||
|
assert(n->Opcode() == Op_UDivI || n->Opcode() == Op_UModI,
|
||||||
|
"only div or mod input pattern accepted");
|
||||||
|
|
||||||
|
UDivModINode* divmod = new UDivModINode(n->in(0), n->in(1), n->in(2));
|
||||||
|
Node* dproj = new ProjNode(divmod, DivModNode::div_proj_num);
|
||||||
|
Node* mproj = new ProjNode(divmod, DivModNode::mod_proj_num);
|
||||||
|
return divmod;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------make------------------------------------------
|
||||||
|
UDivModLNode* UDivModLNode::make(Node* div_or_mod) {
|
||||||
|
Node* n = div_or_mod;
|
||||||
|
assert(n->Opcode() == Op_UDivL || n->Opcode() == Op_UModL,
|
||||||
|
"only div or mod input pattern accepted");
|
||||||
|
|
||||||
|
UDivModLNode* divmod = new UDivModLNode(n->in(0), n->in(1), n->in(2));
|
||||||
|
Node* dproj = new ProjNode(divmod, DivModNode::div_proj_num);
|
||||||
|
Node* mproj = new ProjNode(divmod, DivModNode::mod_proj_num);
|
||||||
|
return divmod;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------match------------------------------------------
|
||||||
|
// return result(s) along with their RegMask info
|
||||||
|
Node* UDivModINode::match( const ProjNode *proj, const Matcher *match ) {
|
||||||
|
uint ideal_reg = proj->ideal_reg();
|
||||||
|
RegMask rm;
|
||||||
|
if (proj->_con == div_proj_num) {
|
||||||
|
rm = match->divI_proj_mask();
|
||||||
|
} else {
|
||||||
|
assert(proj->_con == mod_proj_num, "must be div or mod projection");
|
||||||
|
rm = match->modI_proj_mask();
|
||||||
|
}
|
||||||
|
return new MachProjNode(this, proj->_con, rm, ideal_reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------match------------------------------------------
|
||||||
|
// return result(s) along with their RegMask info
|
||||||
|
Node* UDivModLNode::match( const ProjNode *proj, const Matcher *match ) {
|
||||||
|
uint ideal_reg = proj->ideal_reg();
|
||||||
|
RegMask rm;
|
||||||
|
if (proj->_con == div_proj_num) {
|
||||||
|
rm = match->divL_proj_mask();
|
||||||
|
} else {
|
||||||
|
assert(proj->_con == mod_proj_num, "must be div or mod projection");
|
||||||
|
rm = match->modL_proj_mask();
|
||||||
|
}
|
||||||
|
return new MachProjNode(this, proj->_con, rm, ideal_reg);
|
||||||
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -90,6 +90,32 @@ public:
|
|||||||
virtual uint ideal_reg() const { return Op_RegD; }
|
virtual uint ideal_reg() const { return Op_RegD; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//------------------------------UDivINode---------------------------------------
|
||||||
|
// Unsigned integer division
|
||||||
|
class UDivINode : public Node {
|
||||||
|
public:
|
||||||
|
UDivINode( Node *c, Node *dividend, Node *divisor ) : Node(c, dividend, divisor ) {}
|
||||||
|
virtual int Opcode() const;
|
||||||
|
virtual Node* Identity(PhaseGVN* phase);
|
||||||
|
virtual const Type* Value(PhaseGVN* phase) const;
|
||||||
|
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
|
||||||
|
virtual const Type *bottom_type() const { return TypeInt::INT; }
|
||||||
|
virtual uint ideal_reg() const { return Op_RegI; }
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------UDivLNode---------------------------------------
|
||||||
|
// Unsigned long division
|
||||||
|
class UDivLNode : public Node {
|
||||||
|
public:
|
||||||
|
UDivLNode( Node *c, Node *dividend, Node *divisor ) : Node(c, dividend, divisor ) {}
|
||||||
|
virtual int Opcode() const;
|
||||||
|
virtual Node* Identity(PhaseGVN* phase);
|
||||||
|
virtual const Type* Value(PhaseGVN* phase) const;
|
||||||
|
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
|
||||||
|
virtual const Type *bottom_type() const { return TypeLong::LONG; }
|
||||||
|
virtual uint ideal_reg() const { return Op_RegL; }
|
||||||
|
};
|
||||||
|
|
||||||
//------------------------------ModINode---------------------------------------
|
//------------------------------ModINode---------------------------------------
|
||||||
// Integer modulus
|
// Integer modulus
|
||||||
class ModINode : public Node {
|
class ModINode : public Node {
|
||||||
@ -136,6 +162,28 @@ public:
|
|||||||
virtual uint ideal_reg() const { return Op_RegD; }
|
virtual uint ideal_reg() const { return Op_RegD; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//------------------------------UModINode---------------------------------------
|
||||||
|
// Unsigned integer modulus
|
||||||
|
class UModINode : public Node {
|
||||||
|
public:
|
||||||
|
UModINode( Node *c, Node *in1, Node *in2 ) : Node(c,in1, in2) {}
|
||||||
|
virtual int Opcode() const;
|
||||||
|
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
|
||||||
|
virtual const Type *bottom_type() const { return TypeInt::INT; }
|
||||||
|
virtual uint ideal_reg() const { return Op_RegI; }
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------UModLNode---------------------------------------
|
||||||
|
// Unsigned long modulus
|
||||||
|
class UModLNode : public Node {
|
||||||
|
public:
|
||||||
|
UModLNode( Node *c, Node *in1, Node *in2 ) : Node(c,in1, in2) {}
|
||||||
|
virtual int Opcode() const;
|
||||||
|
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
|
||||||
|
virtual const Type *bottom_type() const { return TypeLong::LONG; }
|
||||||
|
virtual uint ideal_reg() const { return Op_RegL; }
|
||||||
|
};
|
||||||
|
|
||||||
//------------------------------DivModNode---------------------------------------
|
//------------------------------DivModNode---------------------------------------
|
||||||
// Division with remainder result.
|
// Division with remainder result.
|
||||||
class DivModNode : public MultiNode {
|
class DivModNode : public MultiNode {
|
||||||
@ -184,4 +232,31 @@ public:
|
|||||||
static DivModLNode* make(Node* div_or_mod);
|
static DivModLNode* make(Node* div_or_mod);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------UDivModINode---------------------------------------
|
||||||
|
// Unsigend integer division with remainder result.
|
||||||
|
class UDivModINode : public DivModNode {
|
||||||
|
public:
|
||||||
|
UDivModINode( Node *c, Node *dividend, Node *divisor ) : DivModNode(c, dividend, divisor) {}
|
||||||
|
virtual int Opcode() const;
|
||||||
|
virtual const Type *bottom_type() const { return TypeTuple::INT_PAIR; }
|
||||||
|
virtual Node *match( const ProjNode *proj, const Matcher *m );
|
||||||
|
|
||||||
|
// Make a divmod and associated projections from a div or mod.
|
||||||
|
static UDivModINode* make(Node* div_or_mod);
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------UDivModLNode---------------------------------------
|
||||||
|
// Unsigned long division with remainder result.
|
||||||
|
class UDivModLNode : public DivModNode {
|
||||||
|
public:
|
||||||
|
UDivModLNode( Node *c, Node *dividend, Node *divisor ) : DivModNode(c, dividend, divisor) {}
|
||||||
|
virtual int Opcode() const;
|
||||||
|
virtual const Type *bottom_type() const { return TypeTuple::LONG_PAIR; }
|
||||||
|
virtual Node *match( const ProjNode *proj, const Matcher *m );
|
||||||
|
|
||||||
|
// Make a divmod and associated projections from a div or mod.
|
||||||
|
static UDivModLNode* make(Node* div_or_mod);
|
||||||
|
};
|
||||||
|
|
||||||
#endif // SHARE_OPTO_DIVNODE_HPP
|
#endif // SHARE_OPTO_DIVNODE_HPP
|
||||||
|
@ -527,6 +527,11 @@ bool LibraryCallKit::try_to_inline(int predicate) {
|
|||||||
case vmIntrinsics::_reverseBytes_s:
|
case vmIntrinsics::_reverseBytes_s:
|
||||||
case vmIntrinsics::_reverseBytes_c: return inline_number_methods(intrinsic_id());
|
case vmIntrinsics::_reverseBytes_c: return inline_number_methods(intrinsic_id());
|
||||||
|
|
||||||
|
case vmIntrinsics::_divideUnsigned_i:
|
||||||
|
case vmIntrinsics::_divideUnsigned_l:
|
||||||
|
case vmIntrinsics::_remainderUnsigned_i:
|
||||||
|
case vmIntrinsics::_remainderUnsigned_l: return inline_divmod_methods(intrinsic_id());
|
||||||
|
|
||||||
case vmIntrinsics::_getCallerClass: return inline_native_Reflection_getCallerClass();
|
case vmIntrinsics::_getCallerClass: return inline_native_Reflection_getCallerClass();
|
||||||
|
|
||||||
case vmIntrinsics::_Reference_get: return inline_reference_get();
|
case vmIntrinsics::_Reference_get: return inline_reference_get();
|
||||||
@ -2188,6 +2193,39 @@ bool LibraryCallKit::inline_number_methods(vmIntrinsics::ID id) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------inline_unsigned_divmod_methods-----------------------------
|
||||||
|
// inline int Integer.divideUnsigned(init, int)
|
||||||
|
// inline int Integer.remainderUnsigned(int, int)
|
||||||
|
bool LibraryCallKit::inline_divmod_methods(vmIntrinsics::ID id) {
|
||||||
|
Node* n = NULL;
|
||||||
|
switch(id) {
|
||||||
|
case vmIntrinsics::_divideUnsigned_i:
|
||||||
|
zero_check_int(argument(1));
|
||||||
|
// Compile-time detect of null-exception?
|
||||||
|
if (stopped()) return false;
|
||||||
|
n = new UDivINode(control(), argument(0), argument(1));
|
||||||
|
break;
|
||||||
|
case vmIntrinsics::_divideUnsigned_l:
|
||||||
|
zero_check_long(argument(2));
|
||||||
|
// Compile-time detect of null-exception?
|
||||||
|
if (stopped()) return false;
|
||||||
|
n = new UDivLNode(control(), argument(0), argument(2)); break;
|
||||||
|
case vmIntrinsics::_remainderUnsigned_i:
|
||||||
|
zero_check_int(argument(1));
|
||||||
|
// Compile-time detect of null-exception?
|
||||||
|
if (stopped()) return false;
|
||||||
|
n = new UModINode(control(), argument(0), argument(1)); break;
|
||||||
|
case vmIntrinsics::_remainderUnsigned_l:
|
||||||
|
zero_check_long(argument(2));
|
||||||
|
// Compile-time detect of null-exception?
|
||||||
|
if (stopped()) return false;
|
||||||
|
n = new UModLNode(control(), argument(0), argument(2)); break;
|
||||||
|
default: fatal_unexpected_iid(id); break;
|
||||||
|
}
|
||||||
|
set_result(_gvn.transform(n));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------inline_unsafe_access----------------------------
|
//----------------------------inline_unsafe_access----------------------------
|
||||||
|
|
||||||
const TypeOopPtr* LibraryCallKit::sharpen_unsafe_type(Compile::AliasType* alias_type, const TypePtr *adr_type) {
|
const TypeOopPtr* LibraryCallKit::sharpen_unsafe_type(Compile::AliasType* alias_type, const TypePtr *adr_type) {
|
||||||
|
@ -264,6 +264,7 @@ class LibraryCallKit : public GraphKit {
|
|||||||
bool inline_onspinwait();
|
bool inline_onspinwait();
|
||||||
bool inline_fp_conversions(vmIntrinsics::ID id);
|
bool inline_fp_conversions(vmIntrinsics::ID id);
|
||||||
bool inline_number_methods(vmIntrinsics::ID id);
|
bool inline_number_methods(vmIntrinsics::ID id);
|
||||||
|
bool inline_divmod_methods(vmIntrinsics::ID id);
|
||||||
bool inline_reference_get();
|
bool inline_reference_get();
|
||||||
bool inline_reference_refersTo0(bool is_phantom);
|
bool inline_reference_refersTo0(bool is_phantom);
|
||||||
bool inline_Class_cast();
|
bool inline_Class_cast();
|
||||||
|
@ -1579,13 +1579,19 @@
|
|||||||
declare_c2_type(DivLNode, Node) \
|
declare_c2_type(DivLNode, Node) \
|
||||||
declare_c2_type(DivFNode, Node) \
|
declare_c2_type(DivFNode, Node) \
|
||||||
declare_c2_type(DivDNode, Node) \
|
declare_c2_type(DivDNode, Node) \
|
||||||
|
declare_c2_type(UDivINode, Node) \
|
||||||
|
declare_c2_type(UDivLNode, Node) \
|
||||||
declare_c2_type(ModINode, Node) \
|
declare_c2_type(ModINode, Node) \
|
||||||
declare_c2_type(ModLNode, Node) \
|
declare_c2_type(ModLNode, Node) \
|
||||||
declare_c2_type(ModFNode, Node) \
|
declare_c2_type(ModFNode, Node) \
|
||||||
declare_c2_type(ModDNode, Node) \
|
declare_c2_type(ModDNode, Node) \
|
||||||
|
declare_c2_type(UModINode, Node) \
|
||||||
|
declare_c2_type(UModLNode, Node) \
|
||||||
declare_c2_type(DivModNode, MultiNode) \
|
declare_c2_type(DivModNode, MultiNode) \
|
||||||
declare_c2_type(DivModINode, DivModNode) \
|
declare_c2_type(DivModINode, DivModNode) \
|
||||||
declare_c2_type(DivModLNode, DivModNode) \
|
declare_c2_type(DivModLNode, DivModNode) \
|
||||||
|
declare_c2_type(UDivModINode, DivModNode) \
|
||||||
|
declare_c2_type(UDivModLNode, DivModNode) \
|
||||||
declare_c2_type(BoxLockNode, Node) \
|
declare_c2_type(BoxLockNode, Node) \
|
||||||
declare_c2_type(LoopNode, RegionNode) \
|
declare_c2_type(LoopNode, RegionNode) \
|
||||||
declare_c2_type(CountedLoopNode, LoopNode) \
|
declare_c2_type(CountedLoopNode, LoopNode) \
|
||||||
|
@ -1542,6 +1542,7 @@ public final class Integer extends Number
|
|||||||
* @see #remainderUnsigned
|
* @see #remainderUnsigned
|
||||||
* @since 1.8
|
* @since 1.8
|
||||||
*/
|
*/
|
||||||
|
@IntrinsicCandidate
|
||||||
public static int divideUnsigned(int dividend, int divisor) {
|
public static int divideUnsigned(int dividend, int divisor) {
|
||||||
// In lieu of tricky code, for now just use long arithmetic.
|
// In lieu of tricky code, for now just use long arithmetic.
|
||||||
return (int)(toUnsignedLong(dividend) / toUnsignedLong(divisor));
|
return (int)(toUnsignedLong(dividend) / toUnsignedLong(divisor));
|
||||||
@ -1559,6 +1560,7 @@ public final class Integer extends Number
|
|||||||
* @see #divideUnsigned
|
* @see #divideUnsigned
|
||||||
* @since 1.8
|
* @since 1.8
|
||||||
*/
|
*/
|
||||||
|
@IntrinsicCandidate
|
||||||
public static int remainderUnsigned(int dividend, int divisor) {
|
public static int remainderUnsigned(int dividend, int divisor) {
|
||||||
// In lieu of tricky code, for now just use long arithmetic.
|
// In lieu of tricky code, for now just use long arithmetic.
|
||||||
return (int)(toUnsignedLong(dividend) % toUnsignedLong(divisor));
|
return (int)(toUnsignedLong(dividend) % toUnsignedLong(divisor));
|
||||||
|
@ -1663,6 +1663,7 @@ public final class Long extends Number
|
|||||||
* @see #remainderUnsigned
|
* @see #remainderUnsigned
|
||||||
* @since 1.8
|
* @since 1.8
|
||||||
*/
|
*/
|
||||||
|
@IntrinsicCandidate
|
||||||
public static long divideUnsigned(long dividend, long divisor) {
|
public static long divideUnsigned(long dividend, long divisor) {
|
||||||
/* See Hacker's Delight (2nd ed), section 9.3 */
|
/* See Hacker's Delight (2nd ed), section 9.3 */
|
||||||
if (divisor >= 0) {
|
if (divisor >= 0) {
|
||||||
@ -1685,6 +1686,7 @@ public final class Long extends Number
|
|||||||
* @see #divideUnsigned
|
* @see #divideUnsigned
|
||||||
* @since 1.8
|
* @since 1.8
|
||||||
*/
|
*/
|
||||||
|
@IntrinsicCandidate
|
||||||
public static long remainderUnsigned(long dividend, long divisor) {
|
public static long remainderUnsigned(long dividend, long divisor) {
|
||||||
/* See Hacker's Delight (2nd ed), section 9.3 */
|
/* See Hacker's Delight (2nd ed), section 9.3 */
|
||||||
if (divisor >= 0) {
|
if (divisor >= 0) {
|
||||||
|
@ -0,0 +1,158 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
* @summary Test x86_64 intrinsic for divideUnsigned() and remainderUnsigned() methods for Integer
|
||||||
|
* @requires os.arch=="amd64" | os.arch=="x86_64"
|
||||||
|
* @library /test/lib /
|
||||||
|
* @run driver compiler.intrinsics.TestIntegerUnsignedDivMod
|
||||||
|
*/
|
||||||
|
|
||||||
|
package compiler.intrinsics;
|
||||||
|
import compiler.lib.ir_framework.*;
|
||||||
|
|
||||||
|
public class TestIntegerUnsignedDivMod {
|
||||||
|
private int BUFFER_SIZE;
|
||||||
|
private int[] dividends;
|
||||||
|
private int[] divisors;
|
||||||
|
private int[] quotients;
|
||||||
|
private int[] remainders;
|
||||||
|
final long MAX_UNSIGNED_INT = Integer.toUnsignedLong(0xffff_ffff);
|
||||||
|
long[] inRange = {
|
||||||
|
0L,
|
||||||
|
1L,
|
||||||
|
2L,
|
||||||
|
2147483646L, // MAX_VALUE - 1
|
||||||
|
2147483647L, // MAX_VALUE
|
||||||
|
2147483648L, // MAX_VALUE + 1
|
||||||
|
MAX_UNSIGNED_INT - 1L,
|
||||||
|
MAX_UNSIGNED_INT,
|
||||||
|
};
|
||||||
|
|
||||||
|
public static void main(String args[]) {
|
||||||
|
TestFramework.run(TestIntegerUnsignedDivMod.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TestIntegerUnsignedDivMod() {
|
||||||
|
BUFFER_SIZE = inRange.length * inRange.length;
|
||||||
|
dividends = new int[BUFFER_SIZE];
|
||||||
|
divisors = new int[BUFFER_SIZE];
|
||||||
|
quotients = new int[BUFFER_SIZE];
|
||||||
|
remainders = new int[BUFFER_SIZE];
|
||||||
|
|
||||||
|
int idx = 0;
|
||||||
|
for (int i = 0; i < inRange.length; i++) {
|
||||||
|
for (int j = 0; j < inRange.length; j++){
|
||||||
|
dividends[idx] = (int) inRange[i];
|
||||||
|
divisors[idx] = (int) inRange[j];
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test // needs to be run in (fast) debug mode
|
||||||
|
@Warmup(10000)
|
||||||
|
@IR(counts = {"UDivI", ">= 1"}) // Atleast one UDivI node is generated if intrinsic is used
|
||||||
|
public void testDivideUnsigned() {
|
||||||
|
for (int i = 0; i < BUFFER_SIZE; i++) {
|
||||||
|
try {
|
||||||
|
quotients[i] = Integer.divideUnsigned(dividends[i], divisors[i]);
|
||||||
|
} catch(ArithmeticException ea) {
|
||||||
|
; // expected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
checkResult("divideUnsigned");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test // needs to be run in (fast) debug mode
|
||||||
|
@Warmup(10000)
|
||||||
|
@IR(counts = {"UModI", ">= 1"}) // Atleast one UModI node is generated if intrinsic is used
|
||||||
|
public void testRemainderUnsigned() {
|
||||||
|
for (int i = 0; i < BUFFER_SIZE; i++) {
|
||||||
|
try {
|
||||||
|
remainders[i] = Integer.remainderUnsigned(dividends[i], divisors[i]);
|
||||||
|
} catch(ArithmeticException ea) {
|
||||||
|
; // expected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
checkResult("remainderUnsigned");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test // needs to be run in (fast) debug mode
|
||||||
|
@Warmup(10000)
|
||||||
|
@IR(counts = {"UDivModI", ">= 1"}) // Atleast one UDivModI node is generated if intrinsic is used
|
||||||
|
public void testDivModUnsigned() {
|
||||||
|
for (int i = 0; i < BUFFER_SIZE; i++) {
|
||||||
|
try {
|
||||||
|
divmod(dividends[i], divisors[i], i);
|
||||||
|
} catch(ArithmeticException ea) {
|
||||||
|
; // expected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
checkResult("divmodUnsigned");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void divmod(int dividend, int divisor, int i) {
|
||||||
|
quotients[i] = Integer.divideUnsigned(dividend, divisor);
|
||||||
|
remainders[i] = Integer.remainderUnsigned(dividend, divisor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkResult(String mode) {
|
||||||
|
for (int i=0; i < BUFFER_SIZE; i++) {
|
||||||
|
if (divisors[i] == 0) continue;
|
||||||
|
long dividend = Integer.toUnsignedLong(dividends[i]);
|
||||||
|
long divisor = Integer.toUnsignedLong(divisors[i]);
|
||||||
|
int quo = (int) (dividend / divisor);
|
||||||
|
int rem = (int) (dividend % divisor);
|
||||||
|
boolean mismatch;
|
||||||
|
switch (mode) {
|
||||||
|
case "divideUnsigned": mismatch = (quotients[i] != quo); break;
|
||||||
|
case "remainderUnsigned": mismatch = (remainders[i] != rem); break;
|
||||||
|
case "divmodUnsigned": mismatch = (quotients[i] != quo || remainders[i] != rem); break;
|
||||||
|
default: throw new IllegalArgumentException("incorrect mode");
|
||||||
|
}
|
||||||
|
if (mismatch) {
|
||||||
|
throw new RuntimeException(errorMessage(mode, i, quo, rem));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String errorMessage(String mode, int i, int quo, int rem) {
|
||||||
|
StringBuilder sb = new StringBuilder(mode);
|
||||||
|
sb = sb.append(" test error at index=").append(i);
|
||||||
|
sb = sb.append(": dividend=").append(dividends[i]);
|
||||||
|
sb = sb.append("; divisor= ").append(divisors[i]);
|
||||||
|
if (!mode.equals("remainderUnsigned")) {
|
||||||
|
sb = sb.append("; quotient (expected)= ").append(quo);
|
||||||
|
sb = sb.append("; quotient (actual)= ").append(quotients[i]);
|
||||||
|
}
|
||||||
|
if (!mode.equals("divideUnsigned")) {
|
||||||
|
sb = sb.append("; remainder (expected)= ").append(rem);
|
||||||
|
sb = sb.append("; remainder (actual)= ").append(remainders[i]);
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,210 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
* @summary Test x86_64 intrinsic for divideUnsigned() and remainderUnsigned() methods for Long
|
||||||
|
* @requires os.arch=="amd64" | os.arch=="x86_64"
|
||||||
|
* @library /test/lib /
|
||||||
|
* @run driver compiler.intrinsics.TestLongUnsignedDivMod
|
||||||
|
*/
|
||||||
|
|
||||||
|
package compiler.intrinsics;
|
||||||
|
import compiler.lib.ir_framework.*;
|
||||||
|
import java.math.*;
|
||||||
|
|
||||||
|
public class TestLongUnsignedDivMod {
|
||||||
|
private int BUFFER_SIZE;
|
||||||
|
private long[] dividends;
|
||||||
|
private long[] divisors;
|
||||||
|
private long[] quotients;
|
||||||
|
private long[] remainders;
|
||||||
|
long TWO_31 = 1L << Integer.SIZE - 1;
|
||||||
|
long TWO_32 = 1L << Integer.SIZE;
|
||||||
|
long TWO_33 = 1L << Integer.SIZE + 1;
|
||||||
|
BigInteger NINETEEN = BigInteger.valueOf(19L);
|
||||||
|
BigInteger TWO_63 = BigInteger.ONE.shiftLeft(Long.SIZE - 1);
|
||||||
|
BigInteger TWO_64 = BigInteger.ONE.shiftLeft(Long.SIZE);
|
||||||
|
BigInteger[] inRange = {
|
||||||
|
BigInteger.ZERO,
|
||||||
|
BigInteger.ONE,
|
||||||
|
BigInteger.TEN,
|
||||||
|
NINETEEN,
|
||||||
|
|
||||||
|
BigInteger.valueOf(TWO_31 - 19L),
|
||||||
|
BigInteger.valueOf(TWO_31 - 10L),
|
||||||
|
BigInteger.valueOf(TWO_31 - 1L),
|
||||||
|
BigInteger.valueOf(TWO_31),
|
||||||
|
BigInteger.valueOf(TWO_31 + 1L),
|
||||||
|
BigInteger.valueOf(TWO_31 + 10L),
|
||||||
|
BigInteger.valueOf(TWO_31 + 19L),
|
||||||
|
|
||||||
|
BigInteger.valueOf(TWO_32 - 19L),
|
||||||
|
BigInteger.valueOf(TWO_32 - 10L),
|
||||||
|
BigInteger.valueOf(TWO_32 - 1L),
|
||||||
|
BigInteger.valueOf(TWO_32),
|
||||||
|
BigInteger.valueOf(TWO_32 + 1L),
|
||||||
|
BigInteger.valueOf(TWO_32 + 10L),
|
||||||
|
BigInteger.valueOf(TWO_32 - 19L),
|
||||||
|
|
||||||
|
BigInteger.valueOf(TWO_33 - 19L),
|
||||||
|
BigInteger.valueOf(TWO_33 - 10L),
|
||||||
|
BigInteger.valueOf(TWO_33 - 1L),
|
||||||
|
BigInteger.valueOf(TWO_33),
|
||||||
|
BigInteger.valueOf(TWO_33 + 1L),
|
||||||
|
BigInteger.valueOf(TWO_33 + 10L),
|
||||||
|
BigInteger.valueOf(TWO_33 + 19L),
|
||||||
|
|
||||||
|
TWO_63.subtract(NINETEEN),
|
||||||
|
TWO_63.subtract(BigInteger.TEN),
|
||||||
|
TWO_63.subtract(BigInteger.ONE),
|
||||||
|
TWO_63,
|
||||||
|
TWO_63.add(BigInteger.ONE),
|
||||||
|
TWO_63.add(BigInteger.TEN),
|
||||||
|
TWO_63.add(NINETEEN),
|
||||||
|
|
||||||
|
TWO_64.subtract(NINETEEN),
|
||||||
|
TWO_64.subtract(BigInteger.TEN),
|
||||||
|
TWO_64.subtract(BigInteger.ONE),
|
||||||
|
};
|
||||||
|
|
||||||
|
public static void main(String args[]) {
|
||||||
|
TestFramework.run(TestLongUnsignedDivMod.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TestLongUnsignedDivMod() {
|
||||||
|
BUFFER_SIZE = inRange.length * inRange.length;
|
||||||
|
dividends = new long[BUFFER_SIZE];
|
||||||
|
divisors = new long[BUFFER_SIZE];
|
||||||
|
quotients = new long[BUFFER_SIZE];
|
||||||
|
remainders = new long[BUFFER_SIZE];
|
||||||
|
|
||||||
|
int idx = 0;
|
||||||
|
for (int i = 0; i < inRange.length; i++) {
|
||||||
|
for (int j = 0; j < inRange.length; j++){
|
||||||
|
dividends[idx] = inRange[i].longValue();
|
||||||
|
divisors[idx] = inRange[j].longValue();
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test // needs to be run in (fast) debug mode
|
||||||
|
@Warmup(10000)
|
||||||
|
@IR(counts = {"UDivL", ">= 1"}) // Atleast one UDivL node is generated if intrinsic is used
|
||||||
|
public void testDivideUnsigned() {
|
||||||
|
for (int i = 0; i < BUFFER_SIZE; i++) {
|
||||||
|
try {
|
||||||
|
quotients[i] = Long.divideUnsigned(dividends[i], divisors[i]);
|
||||||
|
} catch(ArithmeticException ea) {
|
||||||
|
; // expected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
checkResult("divideUnsigned");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test // needs to be run in (fast) debug mode
|
||||||
|
@Warmup(10000)
|
||||||
|
@IR(counts = {"UModL", ">= 1"}) // Atleast one UModL node is generated if intrinsic is used
|
||||||
|
public void testRemainderUnsigned() {
|
||||||
|
for (int i = 0; i < BUFFER_SIZE; i++) {
|
||||||
|
try {
|
||||||
|
remainders[i] = Long.remainderUnsigned(dividends[i], divisors[i]);
|
||||||
|
} catch(ArithmeticException ea) {
|
||||||
|
; // expected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
checkResult("remainderUnsigned");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test // needs to be run in (fast) debug mode
|
||||||
|
@Warmup(10000)
|
||||||
|
@IR(counts = {"UDivModL", ">= 1"}) // Atleast one UDivModL node is generated if intrinsic is used
|
||||||
|
public void testDivModUnsigned() {
|
||||||
|
for (int i = 0; i < BUFFER_SIZE; i++) {
|
||||||
|
try {
|
||||||
|
divmod(dividends[i], divisors[i], i);
|
||||||
|
} catch(ArithmeticException ea) {
|
||||||
|
; // expected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
checkResult("divmodUnsigned");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void divmod(long dividend, long divisor, int i) {
|
||||||
|
quotients[i] = Long.divideUnsigned(dividend, divisor);
|
||||||
|
remainders[i] = Long.remainderUnsigned(dividend, divisor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkResult(String mode) {
|
||||||
|
for (int i=0; i < BUFFER_SIZE; i++) {
|
||||||
|
if (divisors[i] == 0) continue;
|
||||||
|
BigInteger dividend = toUnsignedBigInteger(dividends[i]);
|
||||||
|
BigInteger divisor = toUnsignedBigInteger(divisors[i]);
|
||||||
|
|
||||||
|
long quo = dividend.divide(divisor).longValue();
|
||||||
|
long rem = dividend.remainder(divisor).longValue();
|
||||||
|
boolean mismatch;
|
||||||
|
switch (mode) {
|
||||||
|
case "divideUnsigned": mismatch = (quotients[i] != quo); break;
|
||||||
|
case "remainderUnsigned": mismatch = (remainders[i] != rem); break;
|
||||||
|
case "divmodUnsigned": mismatch = (quotients[i] != quo || remainders[i] != rem); break;
|
||||||
|
default: throw new IllegalArgumentException("incorrect mode");
|
||||||
|
}
|
||||||
|
if (mismatch) {
|
||||||
|
throw new RuntimeException(errorMessage(mode, i, quo, rem));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String errorMessage(String mode, int i, long quo, long rem) {
|
||||||
|
StringBuilder sb = new StringBuilder(mode);
|
||||||
|
sb = sb.append(" test error at index=").append(i);
|
||||||
|
sb = sb.append(": dividend=").append(dividends[i]);
|
||||||
|
sb = sb.append("; divisor= ").append(divisors[i]);
|
||||||
|
if (!mode.equals("remainderUnsigned")) {
|
||||||
|
sb = sb.append("; quotient (expected)= ").append(quo);
|
||||||
|
sb = sb.append("; quotient (actual)= ").append(quotients[i]);
|
||||||
|
}
|
||||||
|
if (!mode.equals("divideUnsigned")) {
|
||||||
|
sb = sb.append("; remainder (expected)= ").append(rem);
|
||||||
|
sb = sb.append("; remainder (actual)= ").append(remainders[i]);
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private BigInteger toUnsignedBigInteger(long i) {
|
||||||
|
if (i >= 0L)
|
||||||
|
return BigInteger.valueOf(i);
|
||||||
|
else {
|
||||||
|
int upper = (int) (i >>> 32);
|
||||||
|
int lower = (int) i;
|
||||||
|
|
||||||
|
// return (upper << 32) + lower
|
||||||
|
return (BigInteger.valueOf(Integer.toUnsignedLong(upper))).shiftLeft(32).
|
||||||
|
add(BigInteger.valueOf(Integer.toUnsignedLong(lower)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
98
test/micro/org/openjdk/bench/java/lang/IntegerDivMod.java
Normal file
98
test/micro/org/openjdk/bench/java/lang/IntegerDivMod.java
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
/*
|
||||||
|
* 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.Benchmark;
|
||||||
|
import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||||
|
import org.openjdk.jmh.annotations.Mode;
|
||||||
|
import org.openjdk.jmh.annotations.OutputTimeUnit;
|
||||||
|
import org.openjdk.jmh.annotations.Scope;
|
||||||
|
import org.openjdk.jmh.annotations.Setup;
|
||||||
|
import org.openjdk.jmh.annotations.State;
|
||||||
|
import org.openjdk.jmh.annotations.Param;
|
||||||
|
import java.util.random.RandomGenerator;
|
||||||
|
import java.util.random.RandomGeneratorFactory;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests unsigned division and modulus methods in java.lang.Integer
|
||||||
|
*/
|
||||||
|
@BenchmarkMode(Mode.AverageTime)
|
||||||
|
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
||||||
|
@State(Scope.Thread)
|
||||||
|
public class IntegerDivMod {
|
||||||
|
|
||||||
|
RandomGenerator randomGenerator;
|
||||||
|
|
||||||
|
@Param({"mixed", "positive", "negative"})
|
||||||
|
String divisorType;
|
||||||
|
@Param({"1024"})
|
||||||
|
int BUFFER_SIZE;
|
||||||
|
int[] dividends, divisors, quotients, remainders;
|
||||||
|
|
||||||
|
@Setup
|
||||||
|
public void setup() {
|
||||||
|
dividends = new int[BUFFER_SIZE];
|
||||||
|
divisors = new int[BUFFER_SIZE];
|
||||||
|
quotients = new int[BUFFER_SIZE];
|
||||||
|
remainders = new int[BUFFER_SIZE];
|
||||||
|
RandomGenerator rng = RandomGeneratorFactory.getDefault().create(0);
|
||||||
|
for (int i = 0; i < BUFFER_SIZE; i++) {
|
||||||
|
dividends[i] = rng.nextInt();
|
||||||
|
int divisor = rng.nextInt();
|
||||||
|
if (divisorType.equals("positive")) divisor = Math.abs(divisor);
|
||||||
|
else if (divisorType.equals("negative")) divisor = -Math.abs(divisor);
|
||||||
|
divisors[i] = divisor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public void testDivideUnsigned() {
|
||||||
|
for (int i = 0; i < BUFFER_SIZE; i++) {
|
||||||
|
quotients[i] = Integer.divideUnsigned(dividends[i], divisors[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public void testRemainderUnsigned() {
|
||||||
|
for (int i = 0; i < BUFFER_SIZE; i++) {
|
||||||
|
remainders[i] = Integer.remainderUnsigned(dividends[i], divisors[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public void testDivideRemainderUnsigned() {
|
||||||
|
for (int i = 0; i < BUFFER_SIZE; i++) {
|
||||||
|
divmod(dividends[i], divisors[i], i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void divmod(int dividend, int divisor, int i) {
|
||||||
|
quotients[i] = Integer.divideUnsigned(dividend, divisor);
|
||||||
|
remainders[i] = Integer.remainderUnsigned(dividend, divisor);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
98
test/micro/org/openjdk/bench/java/lang/LongDivMod.java
Normal file
98
test/micro/org/openjdk/bench/java/lang/LongDivMod.java
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
/*
|
||||||
|
* 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.Benchmark;
|
||||||
|
import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||||
|
import org.openjdk.jmh.annotations.Mode;
|
||||||
|
import org.openjdk.jmh.annotations.OutputTimeUnit;
|
||||||
|
import org.openjdk.jmh.annotations.Scope;
|
||||||
|
import org.openjdk.jmh.annotations.Setup;
|
||||||
|
import org.openjdk.jmh.annotations.State;
|
||||||
|
import org.openjdk.jmh.annotations.Param;
|
||||||
|
import java.util.random.RandomGenerator;
|
||||||
|
import java.util.random.RandomGeneratorFactory;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests unsigned division and modulus methods in java.lang.Long
|
||||||
|
*/
|
||||||
|
@BenchmarkMode(Mode.AverageTime)
|
||||||
|
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
||||||
|
@State(Scope.Thread)
|
||||||
|
public class LongDivMod {
|
||||||
|
|
||||||
|
RandomGenerator randomGenerator;
|
||||||
|
|
||||||
|
@Param({"mixed", "positive", "negative"})
|
||||||
|
String divisorType;
|
||||||
|
@Param({"1024"})
|
||||||
|
int BUFFER_SIZE;
|
||||||
|
long[] dividends, divisors, quotients, remainders;
|
||||||
|
|
||||||
|
@Setup
|
||||||
|
public void setup() {
|
||||||
|
dividends = new long[BUFFER_SIZE];
|
||||||
|
divisors = new long[BUFFER_SIZE];
|
||||||
|
quotients = new long[BUFFER_SIZE];
|
||||||
|
remainders = new long[BUFFER_SIZE];
|
||||||
|
RandomGenerator rng = RandomGeneratorFactory.getDefault().create(0);
|
||||||
|
for (int i = 0; i < BUFFER_SIZE; i++) {
|
||||||
|
dividends[i] = rng.nextLong();
|
||||||
|
long divisor = rng.nextLong();
|
||||||
|
if (divisorType.equals("positive")) divisor = Math.abs(divisor);
|
||||||
|
else if (divisorType.equals("negative")) divisor = -Math.abs(divisor);
|
||||||
|
divisors[i] = divisor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public void testDivideUnsigned() {
|
||||||
|
for (int i = 0; i < BUFFER_SIZE; i++) {
|
||||||
|
quotients[i] = Long.divideUnsigned(dividends[i], divisors[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public void testRemainderUnsigned() {
|
||||||
|
for (int i = 0; i < BUFFER_SIZE; i++) {
|
||||||
|
remainders[i] = Long.remainderUnsigned(dividends[i], divisors[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public void testDivideRemainderUnsigned() {
|
||||||
|
for (int i = 0; i < BUFFER_SIZE; i++) {
|
||||||
|
divmod(dividends[i], divisors[i], i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void divmod(long dividend, long divisor, int i) {
|
||||||
|
quotients[i] = Long.divideUnsigned(dividend, divisor);
|
||||||
|
remainders[i] = Long.remainderUnsigned(dividend, divisor);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user