8283894: Intrinsify compress and expand bits on x86

Reviewed-by: psandoz, sviswanathan, jrose, kvn
This commit is contained in:
Jatin Bhateja 2022-06-06 00:37:54 +00:00
parent ebc012ece2
commit f347ff9986
20 changed files with 1115 additions and 30 deletions

View File

@ -11659,20 +11659,70 @@ void Assembler::bzhiq(Register dst, Register src1, Register src2) {
emit_int16((unsigned char)0xF5, (0xC0 | encode));
}
void Assembler::pext(Register dst, Register src1, Register src2) {
void Assembler::pextl(Register dst, Register src1, Register src2) {
assert(VM_Version::supports_bmi2(), "bit manipulation instructions not supported");
InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false);
int encode = vex_prefix_and_encode(dst->encoding(), src1->encoding(), src2->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F_38, &attributes);
emit_int16((unsigned char)0xF5, (0xC0 | encode));
}
void Assembler::pdepl(Register dst, Register src1, Register src2) {
assert(VM_Version::supports_bmi2(), "bit manipulation instructions not supported");
InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false);
int encode = vex_prefix_and_encode(dst->encoding(), src1->encoding(), src2->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_38, &attributes);
emit_int16((unsigned char)0xF5, (0xC0 | encode));
}
void Assembler::pextq(Register dst, Register src1, Register src2) {
assert(VM_Version::supports_bmi2(), "bit manipulation instructions not supported");
InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false);
int encode = vex_prefix_and_encode(dst->encoding(), src1->encoding(), src2->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F_38, &attributes);
emit_int16((unsigned char)0xF5, (0xC0 | encode));
}
void Assembler::pdep(Register dst, Register src1, Register src2) {
void Assembler::pdepq(Register dst, Register src1, Register src2) {
assert(VM_Version::supports_bmi2(), "bit manipulation instructions not supported");
InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false);
int encode = vex_prefix_and_encode(dst->encoding(), src1->encoding(), src2->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_38, &attributes);
emit_int16((unsigned char)0xF5, (0xC0 | encode));
}
void Assembler::pextl(Register dst, Register src1, Address src2) {
assert(VM_Version::supports_bmi2(), "bit manipulation instructions not supported");
InstructionMark im(this);
InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false);
vex_prefix(src2, src1->encoding(), dst->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F_38, &attributes);
emit_int8((unsigned char)0xF5);
emit_operand(dst, src2);
}
void Assembler::pdepl(Register dst, Register src1, Address src2) {
assert(VM_Version::supports_bmi2(), "bit manipulation instructions not supported");
InstructionMark im(this);
InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false);
vex_prefix(src2, src1->encoding(), dst->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_38, &attributes);
emit_int8((unsigned char)0xF5);
emit_operand(dst, src2);
}
void Assembler::pextq(Register dst, Register src1, Address src2) {
assert(VM_Version::supports_bmi2(), "bit manipulation instructions not supported");
InstructionMark im(this);
InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false);
vex_prefix(src2, src1->encoding(), dst->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F_38, &attributes);
emit_int8((unsigned char)0xF5);
emit_operand(dst, src2);
}
void Assembler::pdepq(Register dst, Register src1, Address src2) {
assert(VM_Version::supports_bmi2(), "bit manipulation instructions not supported");
InstructionMark im(this);
InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false);
vex_prefix(src2, src1->encoding(), dst->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_38, &attributes);
emit_int8((unsigned char)0xF5);
emit_operand(dst, src2);
}
void Assembler::sarxl(Register dst, Register src1, Register src2) {
assert(VM_Version::supports_bmi2(), "");
InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ true);

View File

@ -2228,8 +2228,16 @@ private:
void shrxq(Register dst, Address src1, Register src2);
void bzhiq(Register dst, Register src1, Register src2);
void pext(Register dst, Register src1, Register src2);
void pdep(Register dst, Register src1, Register src2);
void pextl(Register dst, Register src1, Register src2);
void pdepl(Register dst, Register src1, Register src2);
void pextq(Register dst, Register src1, Register src2);
void pdepq(Register dst, Register src1, Register src2);
void pextl(Register dst, Register src1, Address src2);
void pdepl(Register dst, Register src1, Address src2);
void pextq(Register dst, Register src1, Address src2);
void pdepq(Register dst, Register src1, Address src2);
//====================VECTOR ARITHMETIC=====================================
// Add Packed Floating-Point Values

View File

@ -4346,7 +4346,7 @@ void C2_MacroAssembler::vector_long_to_maskvec(XMMRegister dst, Register src, Re
int index = 0;
int vindex = 0;
mov64(rtmp1, 0x0101010101010101L);
pdep(rtmp1, src, rtmp1);
pdepq(rtmp1, src, rtmp1);
if (mask_len > 8) {
movq(rtmp2, src);
vpxor(xtmp, xtmp, xtmp, vec_enc);
@ -4363,7 +4363,7 @@ void C2_MacroAssembler::vector_long_to_maskvec(XMMRegister dst, Register src, Re
}
mov64(rtmp1, 0x0101010101010101L);
shrq(rtmp2, 8);
pdep(rtmp1, rtmp2, rtmp1);
pdepq(rtmp1, rtmp2, rtmp1);
pinsrq(xtmp, rtmp1, index % 2);
vindex = index / 2;
if (vindex) {
@ -4504,7 +4504,7 @@ void C2_MacroAssembler::vector_mask_compress(KRegister dst, KRegister src, Regis
kmov(rtmp1, src);
andq(rtmp1, (0xFFFFFFFFFFFFFFFFUL >> (64 - mask_len)));
mov64(rtmp2, -1L);
pext(rtmp2, rtmp2, rtmp1);
pextq(rtmp2, rtmp2, rtmp1);
kmov(dst, rtmp2);
}

View File

@ -1636,6 +1636,16 @@ const bool Matcher::match_rule_supported(int opcode) {
}
break;
#endif // !LP64
case Op_CompressBits:
if (!VM_Version::supports_bmi2() || (!is_LP64 && UseSSE < 2)) {
return false;
}
break;
case Op_ExpandBits:
if (!VM_Version::supports_bmi2() || (!is_LP64 && (UseSSE < 2 || !VM_Version::supports_bmi1()))) {
return false;
}
break;
case Op_SignumF:
if (UseSSE < 1) {
return false;
@ -6248,8 +6258,51 @@ instruct copySignD_imm(regD dst, regD src, regD tmp1, rRegL tmp2, immD zero) %{
%}
ins_pipe( pipe_slow );
%}
#endif // _LP64
//----------------------------- CompressBits/ExpandBits ------------------------
instruct compressBitsI_reg(rRegI dst, rRegI src, rRegI mask) %{
predicate(n->bottom_type()->isa_int());
match(Set dst (CompressBits src mask));
format %{ "pextl $dst, $src, $mask\t! parallel bit extract" %}
ins_encode %{
__ pextl($dst$$Register, $src$$Register, $mask$$Register);
%}
ins_pipe( pipe_slow );
%}
instruct expandBitsI_reg(rRegI dst, rRegI src, rRegI mask) %{
predicate(n->bottom_type()->isa_int());
match(Set dst (ExpandBits src mask));
format %{ "pdepl $dst, $src, $mask\t! parallel bit deposit" %}
ins_encode %{
__ pdepl($dst$$Register, $src$$Register, $mask$$Register);
%}
ins_pipe( pipe_slow );
%}
instruct compressBitsI_mem(rRegI dst, rRegI src, memory mask) %{
predicate(n->bottom_type()->isa_int());
match(Set dst (CompressBits src (LoadI mask)));
format %{ "pextl $dst, $src, $mask\t! parallel bit extract" %}
ins_encode %{
__ pextl($dst$$Register, $src$$Register, $mask$$Address);
%}
ins_pipe( pipe_slow );
%}
instruct expandBitsI_mem(rRegI dst, rRegI src, memory mask) %{
predicate(n->bottom_type()->isa_int());
match(Set dst (ExpandBits src (LoadI mask)));
format %{ "pdepl $dst, $src, $mask\t! parallel bit deposit" %}
ins_encode %{
__ pdepl($dst$$Register, $src$$Register, $mask$$Address);
%}
ins_pipe( pipe_slow );
%}
// --------------------------------- Sqrt --------------------------------------
instruct vsqrtF_reg(vec dst, vec src) %{

View File

@ -213,6 +213,7 @@ reg_class_dynamic long_reg(long_reg_no_ebp, long_reg_with_ebp, %{ PreserveFrameP
// Class of integer register pairs that aligns with calling convention
reg_class eadx_reg( EAX,EDX );
reg_class ebcx_reg( ECX,EBX );
reg_class ebpd_reg( EBP,EDI );
// Not AX or DX, used in divides
reg_class nadx_reg_with_ebp(EBX, ECX, ESI, EDI, EBP);
@ -3928,6 +3929,13 @@ operand eBCXRegL( eRegL reg ) %{
interface(REG_INTER);
%}
operand eBDPRegL( eRegL reg ) %{
constraint(ALLOC_IN_RC(ebpd_reg));
match(reg);
format %{ "EBP:EDI" %}
interface(REG_INTER);
%}
// Special case for integer high multiply
operand eADXRegL_low_only() %{
constraint(ALLOC_IN_RC(eadx_reg));
@ -11507,6 +11515,95 @@ instruct MoveL2D_reg_reg_sse(regD dst, eRegL src, regD tmp) %{
ins_pipe( pipe_slow );
%}
//----------------------------- CompressBits/ExpandBits ------------------------
instruct compressBitsL_reg(eADXRegL dst, eBCXRegL src, eBDPRegL mask, eSIRegI rtmp, regF xtmp, eFlagsReg cr) %{
predicate(n->bottom_type()->isa_long());
match(Set dst (CompressBits src mask));
effect(TEMP rtmp, TEMP xtmp, KILL cr);
format %{ "compress_bits $dst, $src, $mask\t! using $rtmp and $xtmp as TEMP" %}
ins_encode %{
Label exit, partail_result;
// Parallely extract both upper and lower 32 bits of source into destination register pair.
// Merge the results of upper and lower destination registers such that upper destination
// results are contiguously laid out after the lower destination result.
__ pextl($dst$$Register, $src$$Register, $mask$$Register);
__ pextl(HIGH_FROM_LOW($dst$$Register), HIGH_FROM_LOW($src$$Register), HIGH_FROM_LOW($mask$$Register));
__ popcntl($rtmp$$Register, $mask$$Register);
// Skip merging if bit count of lower mask register is equal to 32 (register size).
__ cmpl($rtmp$$Register, 32);
__ jccb(Assembler::equal, exit);
// Due to constraint on number of GPRs on 32 bit target, using XMM register as potential spill slot.
__ movdl($xtmp$$XMMRegister, $rtmp$$Register);
// Shift left the contents of upper destination register by true bit count of lower mask register
// and merge with lower destination register.
__ shlxl($rtmp$$Register, HIGH_FROM_LOW($dst$$Register), $rtmp$$Register);
__ orl($dst$$Register, $rtmp$$Register);
__ movdl($rtmp$$Register, $xtmp$$XMMRegister);
// Zero out upper destination register if true bit count of lower 32 bit mask is zero
// since contents of upper destination have already been copied to lower destination
// register.
__ cmpl($rtmp$$Register, 0);
__ jccb(Assembler::greater, partail_result);
__ movl(HIGH_FROM_LOW($dst$$Register), 0);
__ jmp(exit);
__ bind(partail_result);
// Perform right shift over upper destination register to move out bits already copied
// to lower destination register.
__ subl($rtmp$$Register, 32);
__ negl($rtmp$$Register);
__ shrxl(HIGH_FROM_LOW($dst$$Register), HIGH_FROM_LOW($dst$$Register), $rtmp$$Register);
__ bind(exit);
%}
ins_pipe( pipe_slow );
%}
instruct expandBitsL_reg(eADXRegL dst, eBCXRegL src, eBDPRegL mask, eSIRegI rtmp, regF xtmp, eFlagsReg cr) %{
predicate(n->bottom_type()->isa_long());
match(Set dst (ExpandBits src mask));
effect(TEMP rtmp, TEMP xtmp, KILL cr);
format %{ "expand_bits $dst, $src, $mask\t! using $rtmp and $xtmp as TEMP" %}
ins_encode %{
// Extraction operation sequentially reads the bits from source register starting from LSB
// and lays them out into destination register at bit locations corresponding to true bits
// in mask register. Thus number of source bits read are equal to combined true bit count
// of mask register pair.
Label exit, mask_clipping;
__ pdepl($dst$$Register, $src$$Register, $mask$$Register);
__ pdepl(HIGH_FROM_LOW($dst$$Register), HIGH_FROM_LOW($src$$Register), HIGH_FROM_LOW($mask$$Register));
__ popcntl($rtmp$$Register, $mask$$Register);
// If true bit count of lower mask register is 32 then none of bit of lower source register
// will feed to upper destination register.
__ cmpl($rtmp$$Register, 32);
__ jccb(Assembler::equal, exit);
// Due to constraint on number of GPRs on 32 bit target, using XMM register as potential spill slot.
__ movdl($xtmp$$XMMRegister, $rtmp$$Register);
// Shift right the contents of lower source register to remove already consumed bits.
__ shrxl($rtmp$$Register, $src$$Register, $rtmp$$Register);
// Extract the bits from lower source register starting from LSB under the influence
// of upper mask register.
__ pdepl(HIGH_FROM_LOW($dst$$Register), $rtmp$$Register, HIGH_FROM_LOW($mask$$Register));
__ movdl($rtmp$$Register, $xtmp$$XMMRegister);
__ subl($rtmp$$Register, 32);
__ negl($rtmp$$Register);
__ movdl($xtmp$$XMMRegister, $mask$$Register);
__ movl($mask$$Register, HIGH_FROM_LOW($mask$$Register));
// Clear the set bits in upper mask register which have been used to extract the contents
// from lower source register.
__ bind(mask_clipping);
__ blsrl($mask$$Register, $mask$$Register);
__ decrementl($rtmp$$Register, 1);
__ jccb(Assembler::greater, mask_clipping);
// Starting from LSB extract the bits from upper source register under the influence of
// remaining set bits in upper mask register.
__ pdepl($rtmp$$Register, HIGH_FROM_LOW($src$$Register), $mask$$Register);
// Merge the partial results extracted from lower and upper source register bits.
__ orl(HIGH_FROM_LOW($dst$$Register), $rtmp$$Register);
__ movdl($mask$$Register, $xtmp$$XMMRegister);
__ bind(exit);
%}
ins_pipe( pipe_slow );
%}
// =======================================================================
// fast clearing of an array

View File

@ -9996,6 +9996,48 @@ instruct rorL_rReg_Var(rRegL dst, rcx_RegI shift, rFlagsReg cr)
ins_pipe(ialu_reg_reg);
%}
//----------------------------- CompressBits/ExpandBits ------------------------
instruct compressBitsL_reg(rRegL dst, rRegL src, rRegL mask) %{
predicate(n->bottom_type()->isa_long());
match(Set dst (CompressBits src mask));
format %{ "pextq $dst, $src, $mask\t! parallel bit extract" %}
ins_encode %{
__ pextq($dst$$Register, $src$$Register, $mask$$Register);
%}
ins_pipe( pipe_slow );
%}
instruct expandBitsL_reg(rRegL dst, rRegL src, rRegL mask) %{
predicate(n->bottom_type()->isa_long());
match(Set dst (ExpandBits src mask));
format %{ "pdepq $dst, $src, $mask\t! parallel bit deposit" %}
ins_encode %{
__ pdepq($dst$$Register, $src$$Register, $mask$$Register);
%}
ins_pipe( pipe_slow );
%}
instruct compressBitsL_mem(rRegL dst, rRegL src, memory mask) %{
predicate(n->bottom_type()->isa_long());
match(Set dst (CompressBits src (LoadL mask)));
format %{ "pextq $dst, $src, $mask\t! parallel bit extract" %}
ins_encode %{
__ pextq($dst$$Register, $src$$Register, $mask$$Address);
%}
ins_pipe( pipe_slow );
%}
instruct expandBitsL_mem(rRegL dst, rRegL src, memory mask) %{
predicate(n->bottom_type()->isa_long());
match(Set dst (ExpandBits src (LoadL mask)));
format %{ "pdepq $dst, $src, $mask\t! parallel bit deposit" %}
ins_encode %{
__ pdepq($dst$$Register, $src$$Register, $mask$$Address);
%}
ins_pipe( pipe_slow );
%}
// Logical Instructions

View File

@ -147,6 +147,7 @@ class methodHandle;
do_name(fma_name, "fma") \
do_name(copySign_name, "copySign") \
do_name(signum_name,"signum") \
do_name(expand_name,"expand") \
\
do_intrinsic(_dabs, java_lang_Math, abs_name, double_double_signature, F_S) \
do_intrinsic(_fabs, java_lang_Math, abs_name, float_float_signature, F_S) \
@ -234,6 +235,10 @@ class methodHandle;
\
do_intrinsic(_bitCount_i, java_lang_Integer, bitCount_name, int_int_signature, F_S) \
do_intrinsic(_bitCount_l, java_lang_Long, bitCount_name, long_int_signature, F_S) \
do_intrinsic(_compress_i, java_lang_Integer, compress_name, int2_int_signature, F_S) \
do_intrinsic(_compress_l, java_lang_Long, compress_name, long2_long_signature, F_S) \
do_intrinsic(_expand_i, java_lang_Integer, expand_name, int2_int_signature, F_S) \
do_intrinsic(_expand_l, java_lang_Long, expand_name, long2_long_signature, F_S) \
\
do_intrinsic(_reverseBytes_i, java_lang_Integer, reverseBytes_name, int_int_signature, F_S) \
do_name( reverseBytes_name, "reverseBytes") \
@ -247,7 +252,7 @@ class methodHandle;
do_intrinsic(_identityHashCode, java_lang_System, identityHashCode_name, object_int_signature, F_SN) \
do_name( identityHashCode_name, "identityHashCode") \
do_intrinsic(_currentTimeMillis, java_lang_System, currentTimeMillis_name, void_long_signature, F_SN) \
\
\
do_name( currentTimeMillis_name, "currentTimeMillis") \
do_intrinsic(_nanoTime, java_lang_System, nanoTime_name, void_long_signature, F_SN) \
do_name( nanoTime_name, "nanoTime") \

View File

@ -243,6 +243,14 @@ bool C2Compiler::is_intrinsic_supported(const methodHandle& method, bool is_virt
case vmIntrinsics::_bitCount_l:
if (!Matcher::match_rule_supported(Op_PopCountL)) return false;
break;
case vmIntrinsics::_compress_i:
case vmIntrinsics::_compress_l:
if (!Matcher::match_rule_supported(Op_CompressBits)) return false;
break;
case vmIntrinsics::_expand_i:
case vmIntrinsics::_expand_l:
if (!Matcher::match_rule_supported(Op_ExpandBits)) return false;
break;
case vmIntrinsics::_numberOfLeadingZeros_i:
if (!Matcher::match_rule_supported(Op_CountLeadingZerosI)) return false;
break;

View File

@ -24,8 +24,13 @@
#include "precompiled.hpp"
#include "opto/intrinsicnode.hpp"
#include "opto/addnode.hpp"
#include "opto/mulnode.hpp"
#include "opto/memnode.hpp"
#include "opto/phaseX.hpp"
#include "utilities/population_count.hpp"
#include "utilities/count_leading_zeros.hpp"
#include "utilities/globalDefinitions.hpp"
//=============================================================================
// Do not match memory edge.
@ -112,3 +117,236 @@ SignumFNode* SignumFNode::make(PhaseGVN& gvn, Node* in) {
return new SignumFNode(in, gvn.makecon(TypeF::ZERO), gvn.makecon(TypeF::ONE));
}
Node* CompressBitsNode::Ideal(PhaseGVN* phase, bool can_reshape) {
Node* src = in(1);
Node* mask = in(2);
if (bottom_type()->isa_int()) {
if (mask->Opcode() == Op_LShiftI && phase->type(mask->in(1))->is_int()->is_con()) {
// compress(x, 1 << n) == (x >> n & 1)
if (phase->type(mask->in(1))->higher_equal(TypeInt::ONE)) {
Node* rshift = phase->transform(new RShiftINode(in(1), mask->in(2)));
return new AndINode(rshift, phase->makecon(TypeInt::ONE));
// compress(x, -1 << n) == x >>> n
} else if (phase->type(mask->in(1))->higher_equal(TypeInt::MINUS_1)) {
return new URShiftINode(in(1), mask->in(2));
}
}
// compress(expand(x, m), m) == x & compress(m, m)
if (src->Opcode() == Op_ExpandBits &&
src->in(2) == mask) {
Node* compr = phase->transform(new CompressBitsNode(mask, mask, TypeInt::INT));
return new AndINode(compr, src->in(1));
}
} else {
assert(bottom_type()->isa_long(), "");
if (mask->Opcode() == Op_LShiftL && phase->type(mask->in(1))->is_long()->is_con()) {
// compress(x, 1 << n) == (x >> n & 1)
if (phase->type(mask->in(1))->higher_equal(TypeLong::ONE)) {
Node* rshift = phase->transform(new RShiftLNode(in(1), mask->in(2)));
return new AndLNode(rshift, phase->makecon(TypeLong::ONE));
// compress(x, -1 << n) == x >>> n
} else if (phase->type(mask->in(1))->higher_equal(TypeLong::MINUS_1)) {
return new URShiftLNode(in(1), mask->in(2));
}
}
// compress(expand(x, m), m) == x & compress(m, m)
if (src->Opcode() == Op_ExpandBits &&
src->in(2) == mask) {
Node* compr = phase->transform(new CompressBitsNode(mask, mask, TypeLong::LONG));
return new AndLNode(compr, src->in(1));
}
}
return NULL;
}
Node* compress_expand_identity(PhaseGVN* phase, Node* n) {
BasicType bt = n->bottom_type()->basic_type();
// compress(x, 0) == 0, expand(x, 0) == 0
if(phase->type(n->in(2))->higher_equal(TypeInteger::zero(bt))) return n->in(2);
// compress(x, -1) == x, expand(x, -1) == x
if(phase->type(n->in(2))->higher_equal(TypeInteger::minus_1(bt))) return n->in(1);
return n;
// expand(-1, x) == x
if(n->Opcode() == Op_ExpandBits &&
phase->type(n->in(1))->higher_equal(TypeInteger::minus_1(bt))) return n->in(2);
return n;
}
Node* CompressBitsNode::Identity(PhaseGVN* phase) {
return compress_expand_identity(phase, this);
}
Node* ExpandBitsNode::Ideal(PhaseGVN* phase, bool can_reshape) {
Node* src = in(1);
Node* mask = in(2);
if (bottom_type()->isa_int()) {
if (mask->Opcode() == Op_LShiftI && phase->type(mask->in(1))->is_int()->is_con()) {
// expand(x, 1 << n) == (x & 1) << n
if (phase->type(mask->in(1))->higher_equal(TypeInt::ONE)) {
Node* andnode = phase->transform(new AndINode(in(1), phase->makecon(TypeInt::ONE)));
return new LShiftINode(andnode, mask->in(2));
// expand(x, -1 << n) == x << n
} else if (phase->type(mask->in(1))->higher_equal(TypeInt::MINUS_1)) {
return new LShiftINode(in(1), mask->in(2));
}
}
// expand(compress(x, m), m) == x & m
if (src->Opcode() == Op_CompressBits &&
src->in(2) == mask) {
return new AndINode(src->in(1), mask);
}
} else {
assert(bottom_type()->isa_long(), "");
if (mask->Opcode() == Op_LShiftL && phase->type(mask->in(1))->is_long()->is_con()) {
// expand(x, 1 << n) == (x & 1) << n
if (phase->type(mask->in(1))->higher_equal(TypeLong::ONE)) {
Node* andnode = phase->transform(new AndLNode(in(1), phase->makecon(TypeLong::ONE)));
return new LShiftLNode(andnode, mask->in(2));
// expand(x, -1 << n) == x << n
} else if (phase->type(mask->in(1))->higher_equal(TypeLong::MINUS_1)) {
return new LShiftLNode(in(1), mask->in(2));
}
}
// expand(compress(x, m), m) == x & m
if (src->Opcode() == Op_CompressBits &&
src->in(2) == mask) {
return new AndLNode(src->in(1), mask);
}
}
return NULL;
}
Node* ExpandBitsNode::Identity(PhaseGVN* phase) {
return compress_expand_identity(phase, this);
}
static const Type* bitshuffle_value(const TypeInteger* src_type, const TypeInteger* mask_type, int opc, BasicType bt) {
jlong hi = bt == T_INT ? max_jint : max_jlong;
jlong lo = bt == T_INT ? min_jint : min_jlong;
if(mask_type->is_con() && mask_type->get_con_as_long(bt) != -1L) {
jlong maskcon = mask_type->get_con_as_long(bt);
int bitcount = population_count(static_cast<julong>(bt == T_INT ? maskcon & 0xFFFFFFFFL : maskcon));
if (opc == Op_CompressBits) {
// Bit compression selects the source bits corresponding to true mask bits
// and lays them out contiguously at desitination bit poistions starting from
// LSB, remaining higher order bits are set to zero.
// Thus, it will always generates a +ve value i.e. sign bit set to 0 if
// any bit of constant mask value is zero.
lo = 0L;
hi = (1L << bitcount) - 1;
} else {
assert(opc == Op_ExpandBits, "");
// Expansion sequentially reads source bits starting from LSB
// and places them over destination at bit positions corresponding
// set mask bit. Thus bit expansion for non-negative mask value
// will always generate a +ve value.
hi = maskcon >= 0L ? maskcon : maskcon ^ lo;
lo = maskcon >= 0L ? 0L : lo;
}
}
if (!mask_type->is_con()) {
int mask_max_bw;
int max_bw = bt == T_INT ? 32 : 64;
// Case 1) Mask value range includes -1.
if ((mask_type->lo_as_long() < 0L && mask_type->hi_as_long() >= -1L)) {
mask_max_bw = max_bw;
// Case 2) Mask value range is less than -1.
} else if (mask_type->hi_as_long() < -1L) {
mask_max_bw = max_bw - 1;
} else {
// Case 3) Mask value range only includes +ve values.
assert(mask_type->lo_as_long() >= 0, "");
mask_max_bw = max_bw - count_leading_zeros(mask_type->hi_as_long());
}
if ( opc == Op_CompressBits) {
lo = mask_max_bw == max_bw ? lo : 0L;
// Compress operation is inherently an unsigned operation and
// result value range is primarily dependent on true count
// of participating mask value.
hi = mask_max_bw < max_bw ? (1L << mask_max_bw) - 1 : src_type->hi_as_long();
} else {
assert(opc == Op_ExpandBits, "");
jlong max_mask = mask_type->hi_as_long();
lo = mask_type->lo_as_long() >= 0L ? 0L : lo;
hi = mask_type->lo_as_long() >= 0L ? max_mask : hi;
}
}
return bt == T_INT ? static_cast<const Type*>(TypeInt::make(lo, hi, Type::WidenMax)) :
static_cast<const Type*>(TypeLong::make(lo, hi, Type::WidenMax));
}
jlong CompressBitsNode::compress_bits(jlong src, jlong mask, int bit_count) {
jlong res = 0;
for (int i = 0, j = 0; i < bit_count; i++) {
if(mask & 0x1) {
res |= (src & 0x1) << j++;
}
src >>= 1;
mask >>= 1;
}
return res;
}
const Type* CompressBitsNode::Value(PhaseGVN* phase) const {
const Type* t1 = phase->type(in(1));
const Type* t2 = phase->type(in(2));
if (t1 == Type::TOP || t2 == Type::TOP) {
return Type::TOP;
}
BasicType bt = bottom_type()->basic_type();
const TypeInteger* src_type = t1->is_integer(bt);
const TypeInteger* mask_type = t2->is_integer(bt);
int w = bt == T_INT ? 32 : 64;
// Constant fold if both src and mask are constants.
if (src_type->is_con() && mask_type->is_con()) {
jlong src = src_type->get_con_as_long(bt);
jlong mask = mask_type->get_con_as_long(bt);
jlong res = compress_bits(src, mask, w);
return bt == T_INT ? static_cast<const Type*>(TypeInt::make(res)) :
static_cast<const Type*>(TypeLong::make(res));
}
return bitshuffle_value(src_type, mask_type, Op_CompressBits, bt);
}
jlong ExpandBitsNode::expand_bits(jlong src, jlong mask, int bit_count) {
jlong res = 0;
for (int i = 0; i < bit_count; i++) {
if(mask & 0x1) {
res |= (src & 0x1) << i;
src >>= 1;
}
mask >>= 1;
}
return res;
}
const Type* ExpandBitsNode::Value(PhaseGVN* phase) const {
const Type* t1 = phase->type(in(1));
const Type* t2 = phase->type(in(2));
if (t1 == Type::TOP || t2 == Type::TOP) {
return Type::TOP;
}
BasicType bt = bottom_type()->basic_type();
const TypeInteger* src_type = t1->is_integer(bt);
const TypeInteger* mask_type = t2->is_integer(bt);
int w = bt == T_INT ? 32 : 64;
// Constant fold if both src and mask are constants.
if (src_type->is_con() && mask_type->is_con()) {
jlong src = src_type->get_con_as_long(bt);
jlong mask = mask_type->get_con_as_long(bt);
jlong res = expand_bits(src, mask, w);
return bt == T_INT ? static_cast<const Type*>(TypeInt::make(res)) :
static_cast<const Type*>(TypeLong::make(res));
}
return bitshuffle_value(src_type, mask_type, Op_ExpandBits, bt);
}

View File

@ -262,6 +262,33 @@ class SignumFNode : public Node {
virtual uint ideal_reg() const { return Op_RegF; }
};
//----------------------------CompressBits/ExpandBits---------------------------
class CompressBitsNode : public TypeNode {
public:
CompressBitsNode(Node* in1, Node* in2, const Type* type) : TypeNode(type, 3) {
init_req(1, in1);
init_req(2, in2);
}
virtual int Opcode() const;
virtual Node* Ideal(PhaseGVN* phase, bool can_reshape);
virtual Node* Identity(PhaseGVN* phase);
virtual const Type* Value(PhaseGVN* phase) const;
static jlong compress_bits(jlong src, jlong mask, int bit_size);
};
class ExpandBitsNode : public TypeNode {
public:
ExpandBitsNode(Node* in1, Node* in2, const Type* type) : TypeNode(type, 3) {
init_req(1, in1);
init_req(2, in2);
}
virtual int Opcode() const;
virtual Node* Ideal(PhaseGVN* phase, bool can_reshape);
virtual Node* Identity(PhaseGVN* phase);
virtual const Type* Value(PhaseGVN* phase) const;
static jlong expand_bits(jlong src, jlong mask, int bit_size);
};
//---------- IsInfiniteFNode -----------------------------------------------------
class IsInfiniteFNode : public Node {
public:

View File

@ -530,6 +530,11 @@ bool LibraryCallKit::try_to_inline(int predicate) {
case vmIntrinsics::_reverseBytes_s:
case vmIntrinsics::_reverseBytes_c: return inline_number_methods(intrinsic_id());
case vmIntrinsics::_compress_i:
case vmIntrinsics::_compress_l:
case vmIntrinsics::_expand_i:
case vmIntrinsics::_expand_l: return inline_bitshuffle_methods(intrinsic_id());
case vmIntrinsics::_divideUnsigned_i:
case vmIntrinsics::_divideUnsigned_l:
case vmIntrinsics::_remainderUnsigned_i:
@ -2224,6 +2229,24 @@ bool LibraryCallKit::inline_number_methods(vmIntrinsics::ID id) {
return true;
}
//--------------------------inline_bitshuffle_methods-----------------------------
// inline int Integer.compress(int, int)
// inline int Integer.expand(int, int)
// inline long Long.compress(long, long)
// inline long Long.expand(long, long)
bool LibraryCallKit::inline_bitshuffle_methods(vmIntrinsics::ID id) {
Node* n = NULL;
switch (id) {
case vmIntrinsics::_compress_i: n = new CompressBitsNode(argument(0), argument(1), TypeInt::INT); break;
case vmIntrinsics::_expand_i: n = new ExpandBitsNode(argument(0), argument(1), TypeInt::INT); break;
case vmIntrinsics::_compress_l: n = new CompressBitsNode(argument(0), argument(2), TypeLong::LONG); break;
case vmIntrinsics::_expand_l: n = new ExpandBitsNode(argument(0), argument(2), TypeLong::LONG); break;
default: fatal_unexpected_iid(id); break;
}
set_result(_gvn.transform(n));
return true;
}
//--------------------------inline_unsigned_divmod_methods-----------------------------
// inline int Integer.divideUnsigned(int, int)
// inline int Integer.remainderUnsigned(int, int)

View File

@ -276,6 +276,7 @@ class LibraryCallKit : public GraphKit {
bool inline_fp_conversions(vmIntrinsics::ID id);
bool inline_fp_range_check(vmIntrinsics::ID id);
bool inline_number_methods(vmIntrinsics::ID id);
bool inline_bitshuffle_methods(vmIntrinsics::ID id);
bool inline_divmod_methods(vmIntrinsics::ID id);
bool inline_reference_get();
bool inline_reference_refersTo0(bool is_phantom);

View File

@ -389,20 +389,4 @@ public:
virtual uint ideal_reg() const { return Op_RegI; }
};
//------------------------------CompressBitsNode-------------------------------
// CompressBits placeholder node
class CompressBitsNode : public Node {
public:
CompressBitsNode(Node *in1, Node *in2) : Node(0,in1,in2) {}
virtual int Opcode() const;
};
//------------------------------ExpandBitsNode---------------------------------
// ExpandBits placeholder node
class ExpandBitsNode : public Node {
public:
ExpandBitsNode(Node *in1, Node *in2) : Node(0,in1,in2) {}
virtual int Opcode() const;
};
#endif // SHARE_OPTO_MULNODE_HPP

View File

@ -1839,7 +1839,7 @@ public final class Integer extends Number
* @see #expand
* @since 19
*/
// @IntrinsicCandidate
@IntrinsicCandidate
public static int compress(int i, int mask) {
// See Hacker's Delight (2nd ed) section 7.4 Compress, or Generalized Extract
@ -1927,7 +1927,7 @@ public final class Integer extends Number
* @see #compress
* @since 19
*/
// @IntrinsicCandidate
@IntrinsicCandidate
public static int expand(int i, int mask) {
// Save original mask
int originalMask = mask;

View File

@ -1978,7 +1978,7 @@ public final class Long extends Number
* @see #expand
* @since 19
*/
// @IntrinsicCandidate
@IntrinsicCandidate
public static long compress(long i, long mask) {
// See Hacker's Delight (2nd ed) section 7.4 Compress, or Generalized Extract
@ -2066,7 +2066,7 @@ public final class Long extends Number
* @see #compress
* @since 19
*/
// @IntrinsicCandidate
@IntrinsicCandidate
public static long expand(long i, long mask) {
// Save original mask
long originalMask = mask;

View File

@ -0,0 +1,43 @@
/*
* 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.
*
*/
#include "precompiled.hpp"
#include "opto/intrinsicnode.hpp"
#include "unittest.hpp"
TEST_VM(opto, compress_expand_bits) {
ASSERT_EQ(CompressBitsNode::compress_bits(-4LL, -1LL, 64), -4LL);
ASSERT_EQ(CompressBitsNode::compress_bits(-4LL, -1LL, 32), (-4LL & 0xFFFFFFFFLL));
ASSERT_EQ(CompressBitsNode::compress_bits(2147483647LL, -65535LL, 64), 65535LL);
ASSERT_EQ(CompressBitsNode::compress_bits(2147483647LL, -65535LL, 32), 65535LL);
ASSERT_EQ(CompressBitsNode::compress_bits(-2147483648LL, -65535LL, 64), 562949953355776LL);
ASSERT_EQ(CompressBitsNode::compress_bits(-2147483648LL, -65535LL, 32), 65536LL);
ASSERT_EQ(ExpandBitsNode::expand_bits(-4LL, -1LL, 64), -4LL);
ASSERT_EQ(ExpandBitsNode::expand_bits(-4LL, -1LL, 32), (-4LL & 0xFFFFFFFFLL));
ASSERT_EQ(ExpandBitsNode::expand_bits(2147483647LL, -65535LL, 64), 70368744112129LL);
ASSERT_EQ(ExpandBitsNode::expand_bits(2147483647LL, -65535LL, 32), (-65535LL & 0xFFFFFFFFLL));
ASSERT_EQ(ExpandBitsNode::expand_bits(-2147483648LL, -65535LL, 64), -70368744177664LL);
ASSERT_EQ(ExpandBitsNode::expand_bits(-2147483648LL, -65535LL, 32), 0LL);
}

View File

@ -0,0 +1,504 @@
/*
* 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
* @bug 8283894
* @key randomness
* @summary To test various transforms added for bit COMPRESS_BITS and EXPAND_BITS operations
* @requires vm.compiler2.enabled
* @requires vm.cpu.features ~= ".*bmi2.*"
* @requires vm.cpu.features ~= ".*bmi1.*"
* @requires vm.cpu.features ~= ".*sse2.*"
* @library /test/lib /
* @run driver compiler.intrinsics.TestBitShuffleOpers
*/
package compiler.intrinsics;
import java.util.concurrent.Callable;
import compiler.lib.ir_framework.*;
import jdk.test.lib.Utils;
import java.util.Random;
public class TestBitShuffleOpers {
int [] ri;
int [] ai;
int [] bi;
long [] rl;
long [] al;
long [] bl;
//===================== Compress Bits Transforms ================
@Test
@IR(counts = {"RShiftI", " > 0 ", "AndI", " > 0"})
public void test1(int[] ri, int[] ai, int[] bi) {
for (int i = 0; i < ri.length; i++) {
ri[i] = Integer.compress(ai[i], 1 << bi[i]);
}
}
@Run(test = {"test1"}, mode = RunMode.STANDALONE)
public void kernel_test1() {
for (int i = 0; i < 5000; i++) {
test1(ri, ai, bi);
}
}
@Test
@IR(counts = {"URShiftI", " > 0 "})
public void test2(int[] ri, int[] ai, int[] bi) {
for (int i = 0; i < ri.length; i++) {
ri[i] = Integer.compress(ai[i], -1 << bi[i]);
}
}
@Run(test = {"test2"}, mode = RunMode.STANDALONE)
public void kernel_test2() {
for (int i = 0; i < 5000; i++) {
test2(ri, ai, bi);
}
}
@Test
@IR(counts = {"CompressBits", " > 0 ", "AndI" , " > 0 "})
public void test3(int[] ri, int[] ai, int[] bi) {
for (int i = 0; i < ri.length; i++) {
ri[i] = Integer.compress(Integer.expand(ai[i], bi[i]), bi[i]);
}
}
@Run(test = {"test3"}, mode = RunMode.STANDALONE)
public void kernel_test3() {
for (int i = 0; i < 5000; i++) {
test3(ri, ai, bi);
}
}
@Test
@IR(counts = {"RShiftL", " > 0 ", "AndL", " > 0"})
public void test4(long[] rl, long[] al, long[] bl) {
for (int i = 0; i < rl.length; i++) {
rl[i] = Long.compress(al[i], 1L << bl[i]);
}
}
@Run(test = {"test4"}, mode = RunMode.STANDALONE)
public void kernel_test4() {
for (int i = 0; i < 5000; i++) {
test4(rl, al, bl);
}
}
@Test
@IR(counts = {"URShiftL", " > 0 "})
public void test5(long[] rl, long[] al, long[] bl) {
for (int i = 0; i < rl.length; i++) {
rl[i] = Long.compress(al[i], -1L << bl[i]);
}
}
@Run(test = {"test5"}, mode = RunMode.STANDALONE)
public void kernel_test5() {
for (int i = 0; i < 5000; i++) {
test5(rl, al, bl);
}
}
@Test
@IR(counts = {"CompressBits", " > 0 ", "AndL" , " > 0 "})
public void test6(long[] rl, long[] al, long[] bl) {
for (int i = 0; i < rl.length; i++) {
rl[i] = Long.compress(Long.expand(al[i], bl[i]), bl[i]);
}
}
@Run(test = {"test6"}, mode = RunMode.STANDALONE)
public void kernel_test6() {
for (int i = 0; i < 5000; i++) {
test6(rl, al, bl);
}
}
//===================== Expand Bits Transforms ================
@Test
@IR(counts = {"LShiftI", " > 0 ", "AndI", " > 0"})
public void test7(int[] ri, int[] ai, int[] bi) {
for (int i = 0; i < ri.length; i++) {
ri[i] = Integer.expand(ai[i], 1 << bi[i]);
}
}
@Run(test = {"test7"}, mode = RunMode.STANDALONE)
public void kernel_test7() {
for (int i = 0; i < 5000; i++) {
test7(ri, ai, bi);
}
}
@Test
@IR(counts = {"LShiftI", " > 0 "})
public void test8(int[] ri, int[] ai, int[] bi) {
for (int i = 0; i < ri.length; i++) {
ri[i] = Integer.expand(ai[i], -1 << bi[i]);
}
}
@Run(test = {"test8"}, mode = RunMode.STANDALONE)
public void kernel_test8() {
for (int i = 0; i < 5000; i++) {
test8(ri, ai, bi);
}
}
@Test
@IR(counts = {"AndI" , " > 0 "})
public void test9(int[] ri, int[] ai, int[] bi) {
for (int i = 0; i < ri.length; i++) {
ri[i] = Integer.expand(Integer.compress(ai[i], bi[i]), bi[i]);
}
}
@Run(test = {"test9"}, mode = RunMode.STANDALONE)
public void kernel_test9() {
for (int i = 0; i < 5000; i++) {
test9(ri, ai, bi);
}
}
@Test
@IR(counts = {"LShiftL", " > 0 ", "AndL", " > 0"})
public void test10(long[] rl, long[] al, long[] bl) {
for (int i = 0; i < rl.length; i++) {
rl[i] = Long.expand(al[i], 1L << bl[i]);
}
}
@Run(test = {"test10"}, mode = RunMode.STANDALONE)
public void kernel_test10() {
for (int i = 0; i < 5000; i++) {
test10(rl, al, bl);
}
}
@Test
@IR(counts = {"LShiftL", " > 0 "})
public void test11(long[] rl, long[] al, long[] bl) {
for (int i = 0; i < rl.length; i++) {
rl[i] = Long.expand(al[i], -1L << bl[i]);
}
}
@Run(test = {"test11"}, mode = RunMode.STANDALONE)
public void kernel_test11() {
for (int i = 0; i < 5000; i++) {
test11(rl, al, bl);
}
}
@Test
@IR(counts = {"AndL" , " > 0 "})
public void test12(long[] rl, long[] al, long[] bl) {
for (int i = 0; i < rl.length; i++) {
rl[i] = Long.expand(Long.compress(al[i], bl[i]), bl[i]);
}
}
@Run(test = {"test12"}, mode = RunMode.STANDALONE)
public void kernel_test12() {
for (int i = 0; i < 5000; i++) {
test12(rl, al, bl);
}
}
// ================ Compress/ExpandBits Vanilla ================= //
@Test
@IR(counts = {"CompressBits", " > 0 "})
public void test13(int[] ri, int[] ai, int[] bi) {
for (int i = 0; i < ri.length; i++) {
ri[i] = Integer.compress(ai[i], bi[i]);
}
}
@Run(test = {"test13"}, mode = RunMode.STANDALONE)
public void kernel_test13() {
for (int i = 0; i < 5000; i++) {
test13(ri, ai, bi);
}
verifyCompressInts(ri, ai, bi);
}
@Test
@IR(counts = {"CompressBits", " > 0 "})
public void test14(long[] rl, long[] al, long[] bl) {
for (int i = 0; i < rl.length; i++) {
rl[i] = Long.compress(al[i], bl[i]);
}
}
@Run(test = {"test14"}, mode = RunMode.STANDALONE)
public void kernel_test14() {
for (int i = 0; i < 5000; i++) {
test14(rl, al, bl);
}
verifyCompressLongs(rl, al, bl);
}
@Test
@IR(counts = {"ExpandBits", " > 0 "})
public void test15(int[] ri, int[] ai, int[] bi) {
for (int i = 0; i < ri.length; i++) {
ri[i] = Integer.expand(ai[i], bi[i]);
}
}
@Run(test = {"test15"}, mode = RunMode.STANDALONE)
public void kernel_test15() {
for (int i = 0; i < 5000; i++) {
test15(ri, ai, bi);
}
verifyExpandInts(ri, ai, bi);
}
@Test
@IR(counts = {"ExpandBits", " > 0 "})
public void test16(long[] rl, long[] al, long[] bl) {
for (int i = 0; i < rl.length; i++) {
rl[i] = Long.expand(al[i], bl[i]);
}
}
@Run(test = {"test16"}, mode = RunMode.STANDALONE)
public void kernel_test16() {
for (int i = 0; i < 5000; i++) {
test16(rl, al, bl);
}
verifyExpandLongs(rl, al, bl);
}
@Test
public void test17() {
int resI = 0;
long resL = 0L;
for (int i = 0; i < 5000; i++) {
resI = Integer.expand(-1, -1);
verifyExpandInt(resI, -1, -1);
resI = Integer.compress(-1, -1);
verifyCompressInt(resI, -1, -1);
resI = Integer.expand(ai[i&(SIZE-1)], -1);
verifyExpandInt(resI, ai[i&(SIZE-1)], -1);
resI = Integer.expand(ai[i&(SIZE-1)], -2);
verifyExpandInt(resI, ai[i&(SIZE-1)], -2);
resI = Integer.expand(ai[i&(SIZE-1)], 5);
verifyExpandInt(resI, ai[i&(SIZE-1)], 5);
resI = Integer.compress(ai[i&(SIZE-1)], -1);
verifyCompressInt(resI, ai[i&(SIZE-1)], -1);
resI = Integer.compress(ai[i&(SIZE-1)], -2);
verifyCompressInt(resI, ai[i&(SIZE-1)], -2);
resI = Integer.compress(ai[i&(SIZE-1)], 5);
verifyCompressInt(resI, ai[i&(SIZE-1)], 5);
resI = Integer.expand(ai[i&(SIZE-1)], bi[i&(SIZE-1)] & ~(0x10000000));
verifyExpandInt(resI, ai[i&(SIZE-1)], bi[i&(SIZE-1)] & ~(0x10000000));
resI = Integer.expand(ai[i&(SIZE-1)], bi[i&(SIZE-1)] | (0x10000000));
verifyExpandInt(resI, ai[i&(SIZE-1)], bi[i&(SIZE-1)] | (0x10000000));
resI = Integer.compress(ai[i&(SIZE-1)], bi[i&(SIZE-1)] & ~(0x10000000));
verifyCompressInt(resI, ai[i&(SIZE-1)], bi[i&(SIZE-1)] & ~(0x10000000));
resI = Integer.compress(ai[i&(SIZE-1)], bi[i&(SIZE-1)] | (0x10000000));
verifyCompressInt(resI, ai[i&(SIZE-1)], bi[i&(SIZE-1)] | (0x10000000));
resI = Integer.compress(0x12123434, 0xFF00FF00);
verifyCompressInt(resI, 0x12123434, 0xFF00FF00);
resI = Integer.expand(0x12123434, 0xFF00FF00);
verifyExpandInt(resI, 0x12123434, 0xFF00FF00);
resL = Long.expand(-1L, -1L);
verifyExpandLong(resL, -1L, -1L);
resL = Long.compress(-1L, -1L);
verifyCompressLong(resL, -1L, -1L);
resL = Long.compress(0x1212343412123434L, 0xFF00FF00FF00FF00L);
verifyCompressLong(resL, 0x1212343412123434L, 0xFF00FF00FF00FF00L);
resL = Long.expand(0x1212343412123434L, 0xFF00FF00FF00FF00L);
verifyExpandLong(resL, 0x1212343412123434L, 0xFF00FF00FF00FF00L);
resL = Long.expand(al[i&(SIZE-1)], -1);
verifyExpandLong(resL, al[i&(SIZE-1)], -1);
resL = Long.expand(al[i&(SIZE-1)], -2);
verifyExpandLong(resL, al[i&(SIZE-1)], -2);
resL = Long.expand(al[i&(SIZE-1)], 5);
verifyExpandLong(resL, al[i&(SIZE-1)], 5);
resL = Long.compress(al[i&(SIZE-1)], -1);
verifyCompressLong(resL, al[i&(SIZE-1)], -1);
resL = Long.compress(al[i&(SIZE-1)], -2);
verifyCompressLong(resL, al[i&(SIZE-1)], -2);
resL = Long.compress(al[i&(SIZE-1)], 5);
verifyCompressLong(resL, al[i&(SIZE-1)], 5);
resL = Long.expand(al[i&(SIZE-1)], bl[i&(SIZE-1)] & ~(0x10000000));
verifyExpandLong(resL, al[i&(SIZE-1)], bl[i&(SIZE-1)] & ~(0x10000000));
resL = Long.expand(al[i&(SIZE-1)], bl[i&(SIZE-1)] | (0x10000000));
verifyExpandLong(resL, al[i&(SIZE-1)], bl[i&(SIZE-1)] | (0x10000000));
resL = Long.compress(al[i&(SIZE-1)], bl[i&(SIZE-1)] & ~(0x10000000));
verifyCompressLong(resL, al[i&(SIZE-1)], bl[i&(SIZE-1)] & ~(0x10000000));
resL = Long.compress(al[i&(SIZE-1)], bl[i&(SIZE-1)] | (0x10000000));
verifyCompressLong(resL, al[i&(SIZE-1)], bl[i&(SIZE-1)] | (0x10000000));
}
}
private static final Random R = Utils.getRandomInstance();
static int[] fillIntRandom(Callable<int[]> factory) {
try {
int[] arr = factory.call();
for (int i = 0; i < arr.length; i++) {
arr[i] = R.nextInt();
}
return arr;
} catch (Exception e) {
throw new InternalError(e);
}
}
static long[] fillLongRandom(Callable<long[]> factory) {
try {
long[] arr = factory.call();
for (int i = 0; i < arr.length; i++) {
arr[i] = R.nextLong();
}
return arr;
} catch (Exception e) {
throw new InternalError(e);
}
}
static void verifyExpandInt(int actual, int src, int mask) {
int exp = 0;
for(int j = 0, k = 0; j < Integer.SIZE; j++) {
if ((mask & 0x1) == 1) {
exp |= (src & 0x1) << j;
src >>= 1;
}
mask >>= 1;
}
if (actual != exp) {
throw new Error("expand_int: src = " + src + " mask = " + mask +
" acutal = " + actual + " expected = " + exp);
}
}
static void verifyExpandInts(int [] actual_res, int [] inp_arr, int [] mask_arr) {
assert inp_arr.length == mask_arr.length && inp_arr.length == actual_res.length;
for(int i = 0; i < actual_res.length; i++) {
verifyExpandInt(actual_res[i], inp_arr[i], mask_arr[i]);
}
}
static void verifyExpandLong(long actual, long src, long mask) {
long exp = 0;
for(int j = 0, k = 0; j < Long.SIZE; j++) {
if ((mask & 0x1) == 1) {
exp |= (src & 0x1) << j;
src >>= 1;
}
mask >>= 1;
}
if (actual != exp) {
throw new Error("expand_long: src = " + src + " mask = " + mask +
" acutal = " + actual + " expected = " + exp);
}
}
static void verifyExpandLongs(long [] actual_res, long [] inp_arr, long [] mask_arr) {
assert inp_arr.length == mask_arr.length && inp_arr.length == actual_res.length;
for(int i = 0; i < actual_res.length; i++) {
verifyExpandLong(actual_res[i], inp_arr[i], mask_arr[i]);
}
}
static void verifyCompressInt(int actual, int src, int mask) {
int exp = 0;
for(int j = 0, k = 0; j < Integer.SIZE; j++) {
if ((mask & 0x1) == 1) {
exp |= (src & 0x1) << k++;
}
mask >>= 1;
src >>= 1;
}
if (actual != exp) {
throw new Error("compress_int: src = " + src + " mask = " + mask +
" acutal = " + actual + " expected = " + exp);
}
}
static void verifyCompressInts(int [] actual_res, int [] inp_arr, int [] mask_arr) {
assert inp_arr.length == mask_arr.length && inp_arr.length == actual_res.length;
for(int i = 0; i < actual_res.length; i++) {
verifyCompressInt(actual_res[i], inp_arr[i], mask_arr[i]);
}
}
static void verifyCompressLong(long actual, long src, long mask) {
long exp = 0;
for(int j = 0, k = 0; j < Long.SIZE; j++) {
if ((mask & 0x1) == 1) {
exp |= (src & 0x1) << k++;
}
mask >>= 1;
src >>= 1;
}
if (actual != exp) {
throw new Error("compress_long: src = " + src + " mask = " + mask +
" acutal = " + actual + " expected = " + exp);
}
}
static void verifyCompressLongs(long [] actual_res, long [] inp_arr, long [] mask_arr) {
assert inp_arr.length == mask_arr.length && inp_arr.length == actual_res.length;
for(int i = 0; i < actual_res.length; i++) {
verifyCompressLong(actual_res[i], inp_arr[i], mask_arr[i]);
}
}
// ===================================================== //
static final int SIZE = 512;
public TestBitShuffleOpers() {
ri = new int[SIZE];
ai = fillIntRandom(()-> new int[SIZE]);
bi = fillIntRandom(()-> new int[SIZE]);
rl = new long[SIZE];
al = fillLongRandom(() -> new long[SIZE]);
bl = fillLongRandom(() -> new long[SIZE]);
}
public static void main(String[] args) {
TestFramework.runWithFlags("-XX:-TieredCompilation",
"-XX:CompileThresholdScaling=0.3");
}
}

View File

@ -766,7 +766,6 @@ jdk/jfr/jvm/TestWaste.java 8282427 generic-
# jdk_jpackage
############################################################################
# Client manual tests
java/awt/event/MouseEvent/SpuriousExitEnter/SpuriousExitEnter_1.java 7131438,8022539 generic-all

View File

@ -21,10 +21,12 @@
* questions.
*/
// Disabled by default
// @test
/*
* @test
* @summary Test compress expand as if the test methods are the implementation methods
* @key randomness
* @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:DisableIntrinsic=_expand_i,_expand_l,_compress_i,_compress_l CompressExpandSanityTest
* @run testng CompressExpandSanityTest
*/

View File

@ -25,6 +25,7 @@
* @test
* @summary Test compress expand methods
* @key randomness
* @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:DisableIntrinsic=_expand_i,_expand_l,_compress_i,_compress_l CompressExpandTest
* @run testng CompressExpandTest
*/