Skip to content
Permalink
Browse files
8238696: x86: Enumerate all detected CPU features in VM_Version featu…
…re string

Reviewed-by: dholmes, kvn
  • Loading branch information
Vladimir Ivanov committed Mar 12, 2020
1 parent 1f18922 commit 48c48b7a85320e83097c1556e8aba46bebfe6954
@@ -1328,7 +1328,7 @@ void Assembler::aesdec(XMMRegister dst, XMMRegister src) {
}

void Assembler::vaesdec(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) {
assert(VM_Version::supports_vaes(), "");
assert(VM_Version::supports_avx512_vaes(), "");
InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
attributes.set_is_evex_instruction();
int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
@@ -1355,7 +1355,7 @@ void Assembler::aesdeclast(XMMRegister dst, XMMRegister src) {
}

void Assembler::vaesdeclast(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) {
assert(VM_Version::supports_vaes(), "");
assert(VM_Version::supports_avx512_vaes(), "");
InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
attributes.set_is_evex_instruction();
int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
@@ -1381,7 +1381,7 @@ void Assembler::aesenc(XMMRegister dst, XMMRegister src) {
}

void Assembler::vaesenc(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) {
assert(VM_Version::supports_vaes(), "requires vaes support/enabling");
assert(VM_Version::supports_avx512_vaes(), "requires vaes support/enabling");
InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
attributes.set_is_evex_instruction();
int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
@@ -1407,7 +1407,7 @@ void Assembler::aesenclast(XMMRegister dst, XMMRegister src) {
}

void Assembler::vaesenclast(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) {
assert(VM_Version::supports_vaes(), "requires vaes support/enabling");
assert(VM_Version::supports_avx512_vaes(), "requires vaes support/enabling");
InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
attributes.set_is_evex_instruction();
int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
@@ -4103,7 +4103,7 @@ void Assembler::vpmaddwd(XMMRegister dst, XMMRegister nds, XMMRegister src, int

void Assembler::evpdpwssd(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) {
assert(VM_Version::supports_evex(), "");
assert(VM_Version::supports_vnni(), "must support vnni");
assert(VM_Version::supports_avx512_vnni(), "must support vnni");
InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
attributes.set_is_evex_instruction();
int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
@@ -4137,7 +4137,7 @@ void Assembler::popcntl(Register dst, Register src) {
}

void Assembler::vpopcntd(XMMRegister dst, XMMRegister src, int vector_len) {
assert(VM_Version::supports_vpopcntdq(), "must support vpopcntdq feature");
assert(VM_Version::supports_avx512_vpopcntdq(), "must support vpopcntdq feature");
InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
attributes.set_is_evex_instruction();
int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
@@ -6544,7 +6544,7 @@ void Assembler::vpandq(XMMRegister dst, XMMRegister nds, XMMRegister src, int ve
}

void Assembler::vpshldvd(XMMRegister dst, XMMRegister src, XMMRegister shift, int vector_len) {
assert(VM_Version::supports_vbmi2(), "requires vbmi2");
assert(VM_Version::supports_avx512_vbmi2(), "requires vbmi2");
InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
attributes.set_is_evex_instruction();
int encode = vex_prefix_and_encode(dst->encoding(), src->encoding(), shift->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
@@ -6553,7 +6553,7 @@ void Assembler::vpshldvd(XMMRegister dst, XMMRegister src, XMMRegister shift, in
}

void Assembler::vpshrdvd(XMMRegister dst, XMMRegister src, XMMRegister shift, int vector_len) {
assert(VM_Version::supports_vbmi2(), "requires vbmi2");
assert(VM_Version::supports_avx512_vbmi2(), "requires vbmi2");
InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
attributes.set_is_evex_instruction();
int encode = vex_prefix_and_encode(dst->encoding(), src->encoding(), shift->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
@@ -4445,7 +4445,7 @@ void roundDeclast(XMMRegister xmm_reg) {
}

address generate_cipherBlockChaining_decryptVectorAESCrypt() {
assert(VM_Version::supports_vaes(), "need AES instructions and misaligned SSE support");
assert(VM_Version::supports_avx512_vaes(), "need AES instructions and misaligned SSE support");
__ align(CodeEntryAlignment);
StubCodeMark mark(this, "StubRoutines", "cipherBlockChaining_decryptAESCrypt");
address start = __ pc();
@@ -5750,7 +5750,7 @@ address generate_avx_ghash_processBlocks() {

// If vectorization is enabled, check if the number of iterations is at least 64
// If not, then go to ShifTwo processing 2 iterations
if (VM_Version::supports_vbmi2()) {
if (VM_Version::supports_avx512_vbmi2()) {
__ cmpptr(totalNumIter, (AVX3Threshold/64));
__ jcc(Assembler::less, ShiftTwo);

@@ -5874,7 +5874,7 @@ address generate_avx_ghash_processBlocks() {

// If vectorization is enabled, check if the number of iterations is at least 64
// If not, then go to ShiftTwo shifting two numbers at a time
if (VM_Version::supports_vbmi2()) {
if (VM_Version::supports_avx512_vbmi2()) {
__ cmpl(totalNumIter, (AVX3Threshold/64));
__ jcc(Assembler::less, ShiftTwo);

@@ -6466,7 +6466,7 @@ address generate_avx_ghash_processBlocks() {
StubRoutines::_aescrypt_encryptBlock = generate_aescrypt_encryptBlock();
StubRoutines::_aescrypt_decryptBlock = generate_aescrypt_decryptBlock();
StubRoutines::_cipherBlockChaining_encryptAESCrypt = generate_cipherBlockChaining_encryptAESCrypt();
if (VM_Version::supports_vaes() && VM_Version::supports_avx512vl() && VM_Version::supports_avx512dq() ) {
if (VM_Version::supports_avx512_vaes() && VM_Version::supports_avx512vl() && VM_Version::supports_avx512dq() ) {
StubRoutines::_cipherBlockChaining_decryptAESCrypt = generate_cipherBlockChaining_decryptVectorAESCrypt();
StubRoutines::_electronicCodeBook_encryptAESCrypt = generate_electronicCodeBook_encryptAESCrypt();
StubRoutines::_electronicCodeBook_decryptAESCrypt = generate_electronicCodeBook_decryptAESCrypt();
@@ -6475,7 +6475,7 @@ address generate_avx_ghash_processBlocks() {
}
}
if (UseAESCTRIntrinsics) {
if (VM_Version::supports_vaes() && VM_Version::supports_avx512bw() && VM_Version::supports_avx512vl()) {
if (VM_Version::supports_avx512_vaes() && VM_Version::supports_avx512bw() && VM_Version::supports_avx512vl()) {
StubRoutines::x86::_counter_mask_addr = counter_mask_addr();
StubRoutines::_counterMode_AESCrypt = generate_counterMode_VectorAESCrypt();
} else {
@@ -6556,7 +6556,7 @@ address generate_avx_ghash_processBlocks() {
if (UseMulAddIntrinsic) {
StubRoutines::_mulAdd = generate_mulAdd();
}
if (VM_Version::supports_vbmi2()) {
if (VM_Version::supports_avx512_vbmi2()) {
StubRoutines::_bigIntegerRightShiftWorker = generate_bigIntegerRightShift();
StubRoutines::_bigIntegerLeftShiftWorker = generate_bigIntegerLeftShift();
}
@@ -700,9 +700,9 @@ void VM_Version::get_processor_features() {
_features &= ~CPU_AVX512VL;
_features &= ~CPU_AVX512_VPOPCNTDQ;
_features &= ~CPU_AVX512_VPCLMULQDQ;
_features &= ~CPU_VAES;
_features &= ~CPU_VNNI;
_features &= ~CPU_VBMI2;
_features &= ~CPU_AVX512_VAES;
_features &= ~CPU_AVX512_VNNI;
_features &= ~CPU_AVX512_VBMI2;
}

if (UseAVX < 2)
@@ -730,10 +730,14 @@ void VM_Version::get_processor_features() {
_has_intel_jcc_erratum = IntelJccErratumMitigation;
}

char buf[256];
jio_snprintf(buf, sizeof(buf), "(%u cores per cpu, %u threads per core) family %d model %d stepping %d%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
char buf[512];
int res = jio_snprintf(buf, sizeof(buf),
"(%u cores per cpu, %u threads per core) family %d model %d stepping %d"
"%s%s%s%s%s%s%s%s%s%s" "%s%s%s%s%s%s%s%s%s%s" "%s%s%s%s%s%s%s%s%s%s" "%s%s%s%s%s%s%s%s%s%s" "%s%s%s%s%s%s",

cores_per_cpu(), threads_per_core(),
cpu_family(), _model, _stepping,

(supports_cmov() ? ", cmov" : ""),
(supports_cmpxchg8() ? ", cx8" : ""),
(supports_fxsr() ? ", fxsr" : ""),
@@ -744,7 +748,9 @@ void VM_Version::get_processor_features() {
(supports_ssse3()? ", ssse3": ""),
(supports_sse4_1() ? ", sse4.1" : ""),
(supports_sse4_2() ? ", sse4.2" : ""),

(supports_popcnt() ? ", popcnt" : ""),
(supports_vzeroupper() ? ", vzeroupper" : ""),
(supports_avx() ? ", avx" : ""),
(supports_avx2() ? ", avx2" : ""),
(supports_aes() ? ", aes" : ""),
@@ -753,6 +759,7 @@ void VM_Version::get_processor_features() {
(supports_rtm() ? ", rtm" : ""),
(supports_mmx_ext() ? ", mmxext" : ""),
(supports_3dnow_prefetch() ? ", 3dnowpref" : ""),

(supports_lzcnt() ? ", lzcnt": ""),
(supports_sse4a() ? ", sse4a": ""),
(supports_ht() ? ", ht": ""),
@@ -762,12 +769,28 @@ void VM_Version::get_processor_features() {
(supports_bmi1() ? ", bmi1" : ""),
(supports_bmi2() ? ", bmi2" : ""),
(supports_adx() ? ", adx" : ""),
(supports_evex() ? ", evex" : ""),
(supports_evex() ? ", avx512f" : ""),

(supports_avx512dq() ? ", avx512dq" : ""),
(supports_avx512pf() ? ", avx512pf" : ""),
(supports_avx512er() ? ", avx512er" : ""),
(supports_avx512cd() ? ", avx512cd" : ""),
(supports_avx512bw() ? ", avx512bw" : ""),
(supports_avx512vl() ? ", avx512vl" : ""),
(supports_avx512_vpopcntdq() ? ", avx512_vpopcntdq" : ""),
(supports_avx512_vpclmulqdq() ? ", avx512_vpclmulqdq" : ""),
(supports_avx512_vbmi2() ? ", avx512_vbmi2" : ""),
(supports_avx512_vaes() ? ", avx512_vaes" : ""),

(supports_avx512_vnni() ? ", avx512_vnni" : ""),
(supports_sha() ? ", sha" : ""),
(supports_fma() ? ", fma" : ""),
(supports_vbmi2() ? ", vbmi2" : ""),
(supports_vaes() ? ", vaes" : ""),
(supports_vnni() ? ", vnni" : ""));
(supports_clflush() ? ", clflush" : ""),
(supports_clflushopt() ? ", clflushopt" : ""),
(supports_clwb() ? ", clwb" : ""));

assert(res > 0, "not enough temporary space allocated"); // increase 'buf' size

_features_string = os::strdup(buf);

// UseSSE is set to the smaller of what hardware supports and what
@@ -338,17 +338,18 @@ class VM_Version : public Abstract_VM_Version {
#define CPU_AVX512VL ((uint64_t)UCONST64(0x200000000)) // EVEX instructions with smaller vector length
#define CPU_SHA ((uint64_t)UCONST64(0x400000000)) // SHA instructions
#define CPU_FMA ((uint64_t)UCONST64(0x800000000)) // FMA instructions
#define CPU_VZEROUPPER ((uint64_t)UCONST64(0x1000000000)) // Vzeroupper instruction
#define CPU_AVX512_VPOPCNTDQ ((uint64_t)UCONST64(0x2000000000)) // Vector popcount
#define CPU_AVX512_VPCLMULQDQ ((uint64_t)UCONST64(0x4000000000)) //Vector carryless multiplication
#define CPU_VAES ((uint64_t)UCONST64(0x8000000000)) // Vector AES instructions
#define CPU_VNNI ((uint64_t)UCONST64(0x10000000000)) // Vector Neural Network Instructions
#define CPU_VZEROUPPER ((uint64_t)UCONST64(0x1000000000)) // Vzeroupper instruction
#define CPU_AVX512_VPOPCNTDQ ((uint64_t)UCONST64(0x2000000000)) // Vector popcount
#define CPU_AVX512_VPCLMULQDQ ((uint64_t)UCONST64(0x4000000000)) // Vector carryless multiplication
#define CPU_AVX512_VAES ((uint64_t)UCONST64(0x8000000000)) // Vector AES instructions
#define CPU_AVX512_VNNI ((uint64_t)UCONST64(0x10000000000)) // Vector Neural Network Instructions
#define CPU_AVX512_VBMI2 ((uint64_t)UCONST64(0x100000000000)) // VBMI2 shift left double instructions

#define CPU_FLUSH ((uint64_t)UCONST64(0x20000000000)) // flush instruction
#define CPU_FLUSHOPT ((uint64_t)UCONST64(0x40000000000)) // flushopt instruction
#define CPU_CLWB ((uint64_t)UCONST64(0x80000000000)) // clwb instruction
#define CPU_VBMI2 ((uint64_t)UCONST64(0x100000000000)) // VBMI2 shift left double instructions

// NB! When adding new CPU feature detection consider updating feature string in VM_Version::get_processor_features().

enum Extended_Family {
// AMD
@@ -570,11 +571,11 @@ enum Extended_Family {
if (_cpuid_info.sef_cpuid7_ecx.bits.avx512_vpclmulqdq != 0)
result |= CPU_AVX512_VPCLMULQDQ;
if (_cpuid_info.sef_cpuid7_ecx.bits.vaes != 0)
result |= CPU_VAES;
result |= CPU_AVX512_VAES;
if (_cpuid_info.sef_cpuid7_ecx.bits.avx512_vnni != 0)
result |= CPU_VNNI;
result |= CPU_AVX512_VNNI;
if (_cpuid_info.sef_cpuid7_ecx.bits.avx512_vbmi2 != 0)
result |= CPU_VBMI2;
result |= CPU_AVX512_VBMI2;
}
}
if (_cpuid_info.sef_cpuid7_ebx.bits.bmi1 != 0)
@@ -862,11 +863,11 @@ enum Extended_Family {
static bool supports_sha() { return (_features & CPU_SHA) != 0; }
static bool supports_fma() { return (_features & CPU_FMA) != 0 && supports_avx(); }
static bool supports_vzeroupper() { return (_features & CPU_VZEROUPPER) != 0; }
static bool supports_vpopcntdq() { return (_features & CPU_AVX512_VPOPCNTDQ) != 0; }
static bool supports_avx512_vpopcntdq() { return (_features & CPU_AVX512_VPOPCNTDQ) != 0; }
static bool supports_avx512_vpclmulqdq() { return (_features & CPU_AVX512_VPCLMULQDQ) != 0; }
static bool supports_vaes() { return (_features & CPU_VAES) != 0; }
static bool supports_vnni() { return (_features & CPU_VNNI) != 0; }
static bool supports_vbmi2() { return (_features & CPU_VBMI2) != 0; }
static bool supports_avx512_vaes() { return (_features & CPU_AVX512_VAES) != 0; }
static bool supports_avx512_vnni() { return (_features & CPU_AVX512_VNNI) != 0; }
static bool supports_avx512_vbmi2() { return (_features & CPU_AVX512_VBMI2) != 0; }

// Intel features
static bool is_intel_family_core() { return is_intel() &&
@@ -1262,7 +1262,7 @@ const bool Matcher::match_rule_supported(int opcode) {
}
break;
case Op_PopCountVI:
if (!UsePopCountInstruction || !VM_Version::supports_vpopcntdq()) {
if (!UsePopCountInstruction || !VM_Version::supports_avx512_vpopcntdq()) {
return false;
}
break;
@@ -5666,7 +5666,7 @@ instruct vmuladdS2I_reg_avx(vec dst, vec src1, vec src2) %{
// --------------------------------- Vector Multiply Add Add ----------------------------------

instruct vmuladdaddS2I_reg(vec dst, vec src1, vec src2) %{
predicate(VM_Version::supports_vnni());
predicate(VM_Version::supports_avx512_vnni());
match(Set dst (AddVI (MulAddVS2VI src1 src2) dst));
format %{ "evpdpwssd $dst,$src1,$src2\t! muladdadd packedStoI" %}
ins_encode %{
@@ -0,0 +1,84 @@
/*
* Copyright (c) 2020, 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
* @library /test/lib /
*
* @build sun.hotspot.WhiteBox
* @run driver ClassFileInstaller sun.hotspot.WhiteBox
* sun.hotspot.WhiteBox$WhiteBoxPermission
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
* -XX:+WhiteBoxAPI
* CPUInfoTest
*/

import java.util.Set;
import java.util.List;
import jdk.test.lib.Platform;
import sun.hotspot.WhiteBox;
import sun.hotspot.cpuinfo.CPUInfo;

import static jdk.test.lib.Asserts.*;

public class CPUInfoTest {
static final WhiteBox WB = WhiteBox.getWhiteBox();

private static final Set<String> wellKnownCPUFeatures;

static {
if (Platform.isX86() || Platform.isX64()) {
wellKnownCPUFeatures = Set.of(
"adx", "aes", "bmi1", "bmi2", "cmov", "cx8", "fxsr", "mmx", "clmul", "clflush", "clflushopt", "clwb",
"sha", "fma", "popcnt", "vzeroupper", "erms", "rtm", "mmxext", "3dnowpref", "lzcnt", "ht",
"tsc", "tscinvbit", "tscinv", "sse", "sse2", "sse3", "ssse3", "sse4.1", "sse4.2", "sse4a", "avx", "avx2",
"avx512f", "avx512dq", "avx512pf", "avx512er", "avx512cd", "avx512bw", "avx512vl",
"avx512_vpopcntdq", "avx512_vpclmulqdq", "avx512_vbmi2", "avx512_vaes", "avx512_vnni");
} else {
wellKnownCPUFeatures = null;
}
}

public static void main(String args[]) throws Throwable {
System.out.println("WB.getCPUFeatures(): \"" + WB.getCPUFeatures() + "\"");

String additionalCpuInfo = CPUInfo.getAdditionalCPUInfo();
assertTrue(additionalCpuInfo != null);
System.out.println("CPUInfo.getAdditionalCPUInfo(): \"" + additionalCpuInfo + "\"");

List<String> features = CPUInfo.getFeatures();
assertTrue(features != null);
System.out.println("CPUInfo.getFeatures(): " + features);

for (String feature : features) {
assertTrue(CPUInfo.hasFeature(feature), feature);
}

if (wellKnownCPUFeatures != null) {
System.out.println("Well-known CPU features: " + wellKnownCPUFeatures);
assertTrue(wellKnownCPUFeatures.containsAll(features), "not all features are known");
}

System.out.println("TEST PASSED");
}
}

0 comments on commit 48c48b7

Please sign in to comment.