8290322: Optimize Vector.rearrange over byte vectors for AVX512BW targets.
Reviewed-by: kvn, sviswanathan
This commit is contained in:
parent
27af0144ea
commit
38a81913d3
@ -5121,6 +5121,18 @@ void Assembler::pshufb(XMMRegister dst, XMMRegister src) {
|
|||||||
emit_int16(0x00, (0xC0 | encode));
|
emit_int16(0x00, (0xC0 | encode));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Assembler::evpshufb(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) {
|
||||||
|
assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), "");
|
||||||
|
InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true);
|
||||||
|
attributes.set_is_evex_instruction();
|
||||||
|
attributes.set_embedded_opmask_register_specifier(mask);
|
||||||
|
if (merge) {
|
||||||
|
attributes.reset_is_clear_context();
|
||||||
|
}
|
||||||
|
int encode = simd_prefix_and_encode(dst, nds, src, VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
|
||||||
|
emit_int16(0x00, (0xC0 | encode));
|
||||||
|
}
|
||||||
|
|
||||||
void Assembler::vpshufb(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) {
|
void Assembler::vpshufb(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) {
|
||||||
assert(vector_len == AVX_128bit? VM_Version::supports_avx() :
|
assert(vector_len == AVX_128bit? VM_Version::supports_avx() :
|
||||||
vector_len == AVX_256bit? VM_Version::supports_avx2() :
|
vector_len == AVX_256bit? VM_Version::supports_avx2() :
|
||||||
|
@ -1915,6 +1915,8 @@ private:
|
|||||||
void pshufb(XMMRegister dst, XMMRegister src);
|
void pshufb(XMMRegister dst, XMMRegister src);
|
||||||
void pshufb(XMMRegister dst, Address src);
|
void pshufb(XMMRegister dst, Address src);
|
||||||
void vpshufb(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len);
|
void vpshufb(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len);
|
||||||
|
void evpshufb(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len);
|
||||||
|
|
||||||
|
|
||||||
// Shuffle Packed Doublewords
|
// Shuffle Packed Doublewords
|
||||||
void pshufd(XMMRegister dst, XMMRegister src, int mode);
|
void pshufd(XMMRegister dst, XMMRegister src, int mode);
|
||||||
|
@ -5680,3 +5680,49 @@ void C2_MacroAssembler::udivmodL(Register rax, Register divisor, Register rdx, R
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void C2_MacroAssembler::rearrange_bytes(XMMRegister dst, XMMRegister shuffle, XMMRegister src, XMMRegister xtmp1,
|
||||||
|
XMMRegister xtmp2, XMMRegister xtmp3, Register rtmp, KRegister ktmp,
|
||||||
|
int vlen_enc) {
|
||||||
|
assert(VM_Version::supports_avx512bw(), "");
|
||||||
|
// Byte shuffles are inlane operations and indices are determined using
|
||||||
|
// lower 4 bit of each shuffle lane, thus all shuffle indices are
|
||||||
|
// normalized to index range 0-15. This makes sure that all the multiples
|
||||||
|
// of an index value are placed at same relative position in 128 bit
|
||||||
|
// lane i.e. elements corresponding to shuffle indices 16, 32 and 64
|
||||||
|
// will be 16th element in their respective 128 bit lanes.
|
||||||
|
movl(rtmp, 16);
|
||||||
|
evpbroadcastb(xtmp1, rtmp, vlen_enc);
|
||||||
|
|
||||||
|
// Compute a mask for shuffle vector by comparing indices with expression INDEX < 16,
|
||||||
|
// Broadcast first 128 bit lane across entire vector, shuffle the vector lanes using
|
||||||
|
// original shuffle indices and move the shuffled lanes corresponding to true
|
||||||
|
// mask to destination vector.
|
||||||
|
evpcmpb(ktmp, k0, shuffle, xtmp1, Assembler::lt, true, vlen_enc);
|
||||||
|
evshufi64x2(xtmp2, src, src, 0x0, vlen_enc);
|
||||||
|
evpshufb(dst, ktmp, xtmp2, shuffle, false, vlen_enc);
|
||||||
|
|
||||||
|
// Perform above steps with lane comparison expression as INDEX >= 16 && INDEX < 32
|
||||||
|
// and broadcasting second 128 bit lane.
|
||||||
|
evpcmpb(ktmp, k0, shuffle, xtmp1, Assembler::nlt, true, vlen_enc);
|
||||||
|
vpsllq(xtmp2, xtmp1, 0x1, vlen_enc);
|
||||||
|
evpcmpb(ktmp, ktmp, shuffle, xtmp2, Assembler::lt, true, vlen_enc);
|
||||||
|
evshufi64x2(xtmp3, src, src, 0x55, vlen_enc);
|
||||||
|
evpshufb(dst, ktmp, xtmp3, shuffle, true, vlen_enc);
|
||||||
|
|
||||||
|
// Perform above steps with lane comparison expression as INDEX >= 32 && INDEX < 48
|
||||||
|
// and broadcasting third 128 bit lane.
|
||||||
|
evpcmpb(ktmp, k0, shuffle, xtmp2, Assembler::nlt, true, vlen_enc);
|
||||||
|
vpaddb(xtmp1, xtmp1, xtmp2, vlen_enc);
|
||||||
|
evpcmpb(ktmp, ktmp, shuffle, xtmp1, Assembler::lt, true, vlen_enc);
|
||||||
|
evshufi64x2(xtmp3, src, src, 0xAA, vlen_enc);
|
||||||
|
evpshufb(dst, ktmp, xtmp3, shuffle, true, vlen_enc);
|
||||||
|
|
||||||
|
// Perform above steps with lane comparison expression as INDEX >= 48 && INDEX < 64
|
||||||
|
// and broadcasting third 128 bit lane.
|
||||||
|
evpcmpb(ktmp, k0, shuffle, xtmp1, Assembler::nlt, true, vlen_enc);
|
||||||
|
vpsllq(xtmp2, xtmp2, 0x1, vlen_enc);
|
||||||
|
evpcmpb(ktmp, ktmp, shuffle, xtmp2, Assembler::lt, true, vlen_enc);
|
||||||
|
evshufi64x2(xtmp3, src, src, 0xFF, vlen_enc);
|
||||||
|
evpshufb(dst, ktmp, xtmp3, shuffle, true, vlen_enc);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -458,4 +458,7 @@ public:
|
|||||||
|
|
||||||
void vmovmask(BasicType elem_bt, Address dst, XMMRegister src, XMMRegister mask, int vec_enc);
|
void vmovmask(BasicType elem_bt, Address dst, XMMRegister src, XMMRegister mask, int vec_enc);
|
||||||
|
|
||||||
|
void rearrange_bytes(XMMRegister dst, XMMRegister shuffle, XMMRegister src, XMMRegister xtmp1,
|
||||||
|
XMMRegister xtmp2, XMMRegister xtmp3, Register rtmp, KRegister ktmp, int vlen_enc);
|
||||||
|
|
||||||
#endif // CPU_X86_C2_MACROASSEMBLER_X86_HPP
|
#endif // CPU_X86_C2_MACROASSEMBLER_X86_HPP
|
||||||
|
@ -1848,10 +1848,6 @@ const bool Matcher::match_rule_supported_vector(int opcode, int vlen, BasicType
|
|||||||
return false; // Implementation limitation due to how shuffle is loaded
|
return false; // Implementation limitation due to how shuffle is loaded
|
||||||
} else if (size_in_bits == 256 && UseAVX < 2) {
|
} else if (size_in_bits == 256 && UseAVX < 2) {
|
||||||
return false; // Implementation limitation
|
return false; // Implementation limitation
|
||||||
} else if (bt == T_BYTE && size_in_bits > 256 && !VM_Version::supports_avx512_vbmi()) {
|
|
||||||
return false; // Implementation limitation
|
|
||||||
} else if (bt == T_SHORT && size_in_bits > 256 && !VM_Version::supports_avx512bw()) {
|
|
||||||
return false; // Implementation limitation
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Op_VectorLoadMask:
|
case Op_VectorLoadMask:
|
||||||
@ -8529,7 +8525,23 @@ instruct rearrangeB_avx(legVec dst, legVec src, vec shuffle, legVec vtmp1, legVe
|
|||||||
ins_pipe( pipe_slow );
|
ins_pipe( pipe_slow );
|
||||||
%}
|
%}
|
||||||
|
|
||||||
instruct rearrangeB_evex(vec dst, vec src, vec shuffle) %{
|
|
||||||
|
instruct rearrangeB_evex(vec dst, vec src, vec shuffle, vec xtmp1, vec xtmp2, vec xtmp3, kReg ktmp, rRegI rtmp) %{
|
||||||
|
predicate(Matcher::vector_element_basic_type(n) == T_BYTE &&
|
||||||
|
Matcher::vector_length(n) > 32 && !VM_Version::supports_avx512_vbmi());
|
||||||
|
match(Set dst (VectorRearrange src shuffle));
|
||||||
|
effect(TEMP dst, TEMP xtmp1, TEMP xtmp2, TEMP xtmp3, TEMP ktmp, TEMP rtmp);
|
||||||
|
format %{ "vector_rearrange $dst, $shuffle, $src!\t using $xtmp1, $xtmp2, $xtmp3, $rtmp and $ktmp as TEMP" %}
|
||||||
|
ins_encode %{
|
||||||
|
int vlen_enc = vector_length_encoding(this);
|
||||||
|
__ rearrange_bytes($dst$$XMMRegister, $shuffle$$XMMRegister, $src$$XMMRegister,
|
||||||
|
$xtmp1$$XMMRegister, $xtmp2$$XMMRegister, $xtmp3$$XMMRegister,
|
||||||
|
$rtmp$$Register, $ktmp$$KRegister, vlen_enc);
|
||||||
|
%}
|
||||||
|
ins_pipe( pipe_slow );
|
||||||
|
%}
|
||||||
|
|
||||||
|
instruct rearrangeB_evex_vbmi(vec dst, vec src, vec shuffle) %{
|
||||||
predicate(Matcher::vector_element_basic_type(n) == T_BYTE &&
|
predicate(Matcher::vector_element_basic_type(n) == T_BYTE &&
|
||||||
Matcher::vector_length(n) >= 32 && VM_Version::supports_avx512_vbmi());
|
Matcher::vector_length(n) >= 32 && VM_Version::supports_avx512_vbmi());
|
||||||
match(Set dst (VectorRearrange src shuffle));
|
match(Set dst (VectorRearrange src shuffle));
|
||||||
|
@ -0,0 +1,111 @@
|
|||||||
|
/*
|
||||||
|
* 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.jdk.incubator.vector;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
import jdk.incubator.vector.*;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import org.openjdk.jmh.annotations.*;
|
||||||
|
import org.openjdk.jmh.infra.Blackhole;
|
||||||
|
|
||||||
|
@OutputTimeUnit(TimeUnit.MILLISECONDS)
|
||||||
|
@State(Scope.Thread)
|
||||||
|
@Fork(jvmArgsPrepend = {"--add-modules=jdk.incubator.vector"})
|
||||||
|
public class RearrangeBytesBenchmark {
|
||||||
|
@Param({"256", "512", "1024"})
|
||||||
|
int size;
|
||||||
|
|
||||||
|
int [][] shuffles;
|
||||||
|
byte[] byteinp;
|
||||||
|
byte[] byteres;
|
||||||
|
|
||||||
|
static final VectorSpecies<Byte> bspecies64 = ByteVector.SPECIES_64;
|
||||||
|
static final VectorSpecies<Byte> bspecies128 = ByteVector.SPECIES_128;
|
||||||
|
static final VectorSpecies<Byte> bspecies256 = ByteVector.SPECIES_256;
|
||||||
|
static final VectorSpecies<Byte> bspecies512 = ByteVector.SPECIES_512;
|
||||||
|
|
||||||
|
static final byte[] specialvalsbyte = {0, -0, Byte.MIN_VALUE, Byte.MAX_VALUE};
|
||||||
|
|
||||||
|
@Setup(Level.Trial)
|
||||||
|
public void BmSetup() {
|
||||||
|
Random r = new Random(1024);
|
||||||
|
int [] bits = {64, 128, 256, 512};
|
||||||
|
byteinp = new byte[size];
|
||||||
|
byteres = new byte[size];
|
||||||
|
|
||||||
|
for (int i = 4; i < size; i++) {
|
||||||
|
byteinp[i] = (byte)i;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < specialvalsbyte.length; i++) {
|
||||||
|
byteinp[i] = specialvalsbyte[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
shuffles = new int[4][];
|
||||||
|
for (int i = 0; i < bits.length; i++) {
|
||||||
|
int bytes = bits[i] >> 3;
|
||||||
|
shuffles[i] = new int[bytes];
|
||||||
|
for (int j = 0; j < bytes ; j++) {
|
||||||
|
shuffles[i][j] = r.nextInt(bytes - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public void testRearrangeBytes64() {
|
||||||
|
VectorShuffle<Byte> shuffle = VectorShuffle.fromArray(bspecies512, shuffles[3], 0);
|
||||||
|
for (int j = 0; j < bspecies512.loopBound(size); j += bspecies512.length()) {
|
||||||
|
ByteVector.fromArray(bspecies512, byteinp, j)
|
||||||
|
.rearrange(shuffle)
|
||||||
|
.intoArray(byteres, j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Benchmark
|
||||||
|
public void testRearrangeBytes32() {
|
||||||
|
VectorShuffle<Byte> shuffle = VectorShuffle.fromArray(bspecies256, shuffles[2], 0);
|
||||||
|
for (int j = 0; j < bspecies256.loopBound(size); j += bspecies256.length()) {
|
||||||
|
ByteVector.fromArray(bspecies256, byteinp, j)
|
||||||
|
.rearrange(shuffle)
|
||||||
|
.intoArray(byteres, j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Benchmark
|
||||||
|
public void testRearrangeBytes16() {
|
||||||
|
VectorShuffle<Byte> shuffle = VectorShuffle.fromArray(bspecies128, shuffles[1], 0);
|
||||||
|
for (int j = 0; j < bspecies128.loopBound(size); j += bspecies128.length()) {
|
||||||
|
ByteVector.fromArray(bspecies128, byteinp, j)
|
||||||
|
.rearrange(shuffle)
|
||||||
|
.intoArray(byteres, j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Benchmark
|
||||||
|
public void testRearrangeBytes8() {
|
||||||
|
VectorShuffle<Byte> shuffle = VectorShuffle.fromArray(bspecies64, shuffles[0], 0);
|
||||||
|
for (int j = 0; j < bspecies64.loopBound(size); j += bspecies64.length()) {
|
||||||
|
ByteVector.fromArray(bspecies64, byteinp, j)
|
||||||
|
.rearrange(shuffle)
|
||||||
|
.intoArray(byteres, j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user