8352675: Support Intel AVX10 converged vector ISA feature detection

Reviewed-by: sviswanathan, vlivanov, yzheng
This commit is contained in:
Jatin Bhateja 2025-05-09 23:33:32 +00:00
parent 0f2a6c266b
commit 3b336a9da0
15 changed files with 493 additions and 249 deletions

View File

@ -35,8 +35,7 @@
static_field(VM_Version, _rop_protection, bool) \
static_field(VM_Version, _pac_mask, uintptr_t)
#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type) \
declare_toplevel_type(VM_Version)
#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type)
#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant)

View File

@ -29,15 +29,20 @@
// constants required by the Serviceability Agent. This file is
// referenced by vmStructs.cpp.
#define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field) \
volatile_nonstatic_field(JavaFrameAnchor, _last_Java_fp, intptr_t*)
#define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field) \
volatile_nonstatic_field(JavaFrameAnchor, _last_Java_fp, intptr_t*) \
static_field(VM_Version, _features, VM_Version::VM_Features) \
nonstatic_field(VM_Version::VM_Features, _features_bitmap[0], uint64_t) \
static_field(VM_Version::VM_Features, _features_bitmap_size, int)
#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type) \
declare_toplevel_type(VM_Version::VM_Features)
#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant) \
LP64_ONLY(declare_constant(frame::arg_reg_save_area_bytes)) \
declare_constant(frame::interpreter_frame_sender_sp_offset) \
declare_constant(frame::interpreter_frame_last_sp_offset)
declare_constant(frame::arg_reg_save_area_bytes) \
declare_constant(frame::interpreter_frame_sender_sp_offset) \
declare_constant(frame::interpreter_frame_last_sp_offset) \
declare_constant(frame::entry_frame_call_wrapper_offset)
#define VM_LONG_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant)

View File

@ -63,6 +63,11 @@ address VM_Version::_cpuinfo_cont_addr_apx = nullptr;
static BufferBlob* stub_blob;
static const int stub_size = 2000;
int VM_Version::VM_Features::_features_bitmap_size = sizeof(VM_Version::VM_Features::_features_bitmap) / BytesPerLong;
VM_Version::VM_Features VM_Version::_features;
VM_Version::VM_Features VM_Version::_cpu_features;
extern "C" {
typedef void (*get_cpu_info_stub_t)(void*);
typedef void (*detect_virt_stub_t)(uint32_t, uint32_t*);
@ -82,7 +87,7 @@ bool VM_Version::supports_clflush() {
// up. Assembler::flush calls this routine to check that clflush
// is allowed. So, we give the caller a free pass if Universe init
// is still in progress.
assert ((!Universe::is_fully_initialized() || (_features & CPU_FLUSH) != 0), "clflush should be available");
assert ((!Universe::is_fully_initialized() || _features.supports_feature(CPU_FLUSH)), "clflush should be available");
return true;
}
@ -133,7 +138,7 @@ class VM_Version_StubGenerator: public StubCodeGenerator {
const uint32_t CPU_FAMILY_486 = (4 << CPU_FAMILY_SHIFT);
bool use_evex = FLAG_IS_DEFAULT(UseAVX) || (UseAVX > 2);
Label detect_486, cpu486, detect_586, std_cpuid1, std_cpuid4;
Label detect_486, cpu486, detect_586, std_cpuid1, std_cpuid4, std_cpuid24;
Label sef_cpuid, sefsl1_cpuid, ext_cpuid, ext_cpuid1, ext_cpuid5, ext_cpuid7;
Label ext_cpuid8, done, wrapup, vector_save_restore, apx_save_restore_warning;
Label legacy_setup, save_restore_except, legacy_save_restore, start_simd_check;
@ -332,6 +337,17 @@ class VM_Version_StubGenerator: public StubCodeGenerator {
__ movl(Address(rsi, 0), rax);
__ movl(Address(rsi, 4), rdx);
//
// cpuid(0x24) Converged Vector ISA Main Leaf (EAX = 24H, ECX = 0).
//
__ bind(std_cpuid24);
__ movl(rax, 0x24);
__ movl(rcx, 0);
__ cpuid();
__ lea(rsi, Address(rbp, in_bytes(VM_Version::std_cpuid24_offset())));
__ movl(Address(rsi, 0), rax);
__ movl(Address(rsi, 4), rbx);
//
// Extended cpuid(0x80000000)
//
@ -418,13 +434,11 @@ class VM_Version_StubGenerator: public StubCodeGenerator {
__ lea(rsi, Address(rbp, in_bytes(VM_Version::sefsl1_cpuid7_offset())));
__ movl(rax, 0x200000);
__ andl(rax, Address(rsi, 4));
__ cmpl(rax, 0x200000);
__ jcc(Assembler::notEqual, vector_save_restore);
__ jcc(Assembler::equal, vector_save_restore);
// check _cpuid_info.xem_xcr0_eax.bits.apx_f
__ movl(rax, 0x80000);
__ andl(rax, Address(rbp, in_bytes(VM_Version::xem_xcr0_offset()))); // xcr0 bits apx_f
__ cmpl(rax, 0x80000);
__ jcc(Assembler::notEqual, vector_save_restore);
__ jcc(Assembler::equal, vector_save_restore);
#ifndef PRODUCT
bool save_apx = UseAPX;
@ -477,11 +491,15 @@ class VM_Version_StubGenerator: public StubCodeGenerator {
// If UseAVX is uninitialized or is set by the user to include EVEX
if (use_evex) {
// check _cpuid_info.sef_cpuid7_ebx.bits.avx512f
// OR check _cpuid_info.sefsl1_cpuid7_edx.bits.avx10
__ lea(rsi, Address(rbp, in_bytes(VM_Version::sef_cpuid7_offset())));
__ movl(rax, 0x10000);
__ andl(rax, Address(rsi, 4)); // xcr0 bits sse | ymm
__ cmpl(rax, 0x10000);
__ jccb(Assembler::notEqual, legacy_setup); // jump if EVEX is not supported
__ andl(rax, Address(rsi, 4));
__ lea(rsi, Address(rbp, in_bytes(VM_Version::sefsl1_cpuid7_offset())));
__ movl(rbx, 0x80000);
__ andl(rbx, Address(rsi, 4));
__ orl(rax, rbx);
__ jccb(Assembler::equal, legacy_setup); // jump if EVEX is not supported
// check _cpuid_info.xem_xcr0_eax.bits.opmask
// check _cpuid_info.xem_xcr0_eax.bits.zmm512
// check _cpuid_info.xem_xcr0_eax.bits.zmm32
@ -562,8 +580,7 @@ class VM_Version_StubGenerator: public StubCodeGenerator {
__ lea(rsi, Address(rbp, in_bytes(VM_Version::sef_cpuid7_offset())));
__ movl(rax, 0x10000);
__ andl(rax, Address(rsi, 4));
__ cmpl(rax, 0x10000);
__ jcc(Assembler::notEqual, legacy_save_restore);
__ jcc(Assembler::equal, legacy_save_restore);
// check _cpuid_info.xem_xcr0_eax.bits.opmask
// check _cpuid_info.xem_xcr0_eax.bits.zmm512
// check _cpuid_info.xem_xcr0_eax.bits.zmm32
@ -835,7 +852,6 @@ void VM_Version::get_processor_features() {
_cpu = 4; // 486 by default
_model = 0;
_stepping = 0;
_features = 0;
_logical_processors_per_package = 1;
// i486 internal cache is both I&D and has a 16-byte line size
_L1_data_cache_line_size = 16;
@ -851,7 +867,7 @@ void VM_Version::get_processor_features() {
if (cpu_family() > 4) { // it supports CPUID
_features = _cpuid_info.feature_flags(); // These can be changed by VM settings
_cpu_features = _features; // Preserve features
_cpu_features = _features; // Preserve features
// Logical processors are only available on P4s and above,
// and only if hyperthreading is available.
_logical_processors_per_package = logical_processor_count();
@ -900,21 +916,21 @@ void VM_Version::get_processor_features() {
}
if (UseSSE < 4) {
_features &= ~CPU_SSE4_1;
_features &= ~CPU_SSE4_2;
_features.clear_feature(CPU_SSE4_1);
_features.clear_feature(CPU_SSE4_2);
}
if (UseSSE < 3) {
_features &= ~CPU_SSE3;
_features &= ~CPU_SSSE3;
_features &= ~CPU_SSE4A;
_features.clear_feature(CPU_SSE3);
_features.clear_feature(CPU_SSSE3);
_features.clear_feature(CPU_SSE4A);
}
if (UseSSE < 2)
_features &= ~CPU_SSE2;
_features.clear_feature(CPU_SSE2);
if (UseSSE < 1)
_features &= ~CPU_SSE;
_features.clear_feature(CPU_SSE);
//since AVX instructions is slower than SSE in some ZX cpus, force USEAVX=0.
if (is_zx() && ((cpu_family() == 6) || (cpu_family() == 7))) {
@ -980,21 +996,25 @@ void VM_Version::get_processor_features() {
}
if (UseAVX < 3) {
_features &= ~CPU_AVX512F;
_features &= ~CPU_AVX512DQ;
_features &= ~CPU_AVX512CD;
_features &= ~CPU_AVX512BW;
_features &= ~CPU_AVX512VL;
_features &= ~CPU_AVX512_VPOPCNTDQ;
_features &= ~CPU_AVX512_VPCLMULQDQ;
_features &= ~CPU_AVX512_VAES;
_features &= ~CPU_AVX512_VNNI;
_features &= ~CPU_AVX512_VBMI;
_features &= ~CPU_AVX512_VBMI2;
_features &= ~CPU_AVX512_BITALG;
_features &= ~CPU_AVX512_IFMA;
_features &= ~CPU_APX_F;
_features &= ~CPU_AVX512_FP16;
_features.clear_feature(CPU_AVX512F);
_features.clear_feature(CPU_AVX512DQ);
_features.clear_feature(CPU_AVX512CD);
_features.clear_feature(CPU_AVX512BW);
_features.clear_feature(CPU_AVX512ER);
_features.clear_feature(CPU_AVX512PF);
_features.clear_feature(CPU_AVX512VL);
_features.clear_feature(CPU_AVX512_VPOPCNTDQ);
_features.clear_feature(CPU_AVX512_VPCLMULQDQ);
_features.clear_feature(CPU_AVX512_VAES);
_features.clear_feature(CPU_AVX512_VNNI);
_features.clear_feature(CPU_AVX512_VBMI);
_features.clear_feature(CPU_AVX512_VBMI2);
_features.clear_feature(CPU_AVX512_BITALG);
_features.clear_feature(CPU_AVX512_IFMA);
_features.clear_feature(CPU_APX_F);
_features.clear_feature(CPU_AVX512_FP16);
_features.clear_feature(CPU_AVX10_1);
_features.clear_feature(CPU_AVX10_2);
}
// Currently APX support is only enabled for targets supporting AVX512VL feature.
@ -1007,45 +1027,47 @@ void VM_Version::get_processor_features() {
}
if (!UseAPX) {
_features &= ~CPU_APX_F;
_features.clear_feature(CPU_APX_F);
}
if (UseAVX < 2) {
_features &= ~CPU_AVX2;
_features &= ~CPU_AVX_IFMA;
_features.clear_feature(CPU_AVX2);
_features.clear_feature(CPU_AVX_IFMA);
}
if (UseAVX < 1) {
_features &= ~CPU_AVX;
_features &= ~CPU_VZEROUPPER;
_features &= ~CPU_F16C;
_features &= ~CPU_SHA512;
_features.clear_feature(CPU_AVX);
_features.clear_feature(CPU_VZEROUPPER);
_features.clear_feature(CPU_F16C);
_features.clear_feature(CPU_SHA512);
}
if (logical_processors_per_package() == 1) {
// HT processor could be installed on a system which doesn't support HT.
_features &= ~CPU_HT;
_features.clear_feature(CPU_HT);
}
if (is_intel()) { // Intel cpus specific settings
if (is_knights_family()) {
_features &= ~CPU_VZEROUPPER;
_features &= ~CPU_AVX512BW;
_features &= ~CPU_AVX512VL;
_features &= ~CPU_AVX512DQ;
_features &= ~CPU_AVX512_VNNI;
_features &= ~CPU_AVX512_VAES;
_features &= ~CPU_AVX512_VPOPCNTDQ;
_features &= ~CPU_AVX512_VPCLMULQDQ;
_features &= ~CPU_AVX512_VBMI;
_features &= ~CPU_AVX512_VBMI2;
_features &= ~CPU_CLWB;
_features &= ~CPU_FLUSHOPT;
_features &= ~CPU_GFNI;
_features &= ~CPU_AVX512_BITALG;
_features &= ~CPU_AVX512_IFMA;
_features &= ~CPU_AVX_IFMA;
_features &= ~CPU_AVX512_FP16;
_features.clear_feature(CPU_VZEROUPPER);
_features.clear_feature(CPU_AVX512BW);
_features.clear_feature(CPU_AVX512VL);
_features.clear_feature(CPU_AVX512DQ);
_features.clear_feature(CPU_AVX512_VNNI);
_features.clear_feature(CPU_AVX512_VAES);
_features.clear_feature(CPU_AVX512_VPOPCNTDQ);
_features.clear_feature(CPU_AVX512_VPCLMULQDQ);
_features.clear_feature(CPU_AVX512_VBMI);
_features.clear_feature(CPU_AVX512_VBMI2);
_features.clear_feature(CPU_CLWB);
_features.clear_feature(CPU_FLUSHOPT);
_features.clear_feature(CPU_GFNI);
_features.clear_feature(CPU_AVX512_BITALG);
_features.clear_feature(CPU_AVX512_IFMA);
_features.clear_feature(CPU_AVX_IFMA);
_features.clear_feature(CPU_AVX512_FP16);
_features.clear_feature(CPU_AVX10_1);
_features.clear_feature(CPU_AVX10_2);
}
}
@ -1055,7 +1077,6 @@ void VM_Version::get_processor_features() {
_has_intel_jcc_erratum = IntelJccErratumMitigation;
}
assert(supports_cpuid(), "Always present");
assert(supports_clflush(), "Always present");
if (X86ICacheSync == -1) {
// Auto-detect, choosing the best performant one that still flushes
@ -1079,14 +1100,15 @@ void VM_Version::get_processor_features() {
}
}
char buf[1024];
int cpu_info_size = jio_snprintf(
char buf[2048];
size_t cpu_info_size = jio_snprintf(
buf, sizeof(buf),
"(%u cores per cpu, %u threads per core) family %d model %d stepping %d microcode 0x%x",
cores_per_cpu(), threads_per_core(),
cpu_family(), _model, _stepping, os::cpu_microcode_revision());
assert(cpu_info_size > 0, "not enough temporary space allocated");
insert_features_names(buf + cpu_info_size, sizeof(buf) - cpu_info_size, _features_names);
insert_features_names(_features, buf + cpu_info_size, sizeof(buf) - cpu_info_size);
_cpu_info_string = os::strdup(buf);
@ -2088,6 +2110,7 @@ static bool _vm_version_initialized = false;
void VM_Version::initialize() {
ResourceMark rm;
// Making this stub must be FIRST use of assembler
stub_blob = BufferBlob::create("VM_Version stub", stub_size);
if (stub_blob == nullptr) {
@ -2863,185 +2886,212 @@ int64_t VM_Version::maximum_qualified_cpu_frequency(void) {
return _max_qualified_cpu_frequency;
}
uint64_t VM_Version::CpuidInfo::feature_flags() const {
uint64_t result = 0;
VM_Version::VM_Features VM_Version::CpuidInfo::feature_flags() const {
VM_Features vm_features;
if (std_cpuid1_edx.bits.cmpxchg8 != 0)
result |= CPU_CX8;
vm_features.set_feature(CPU_CX8);
if (std_cpuid1_edx.bits.cmov != 0)
result |= CPU_CMOV;
vm_features.set_feature(CPU_CMOV);
if (std_cpuid1_edx.bits.clflush != 0)
result |= CPU_FLUSH;
vm_features.set_feature(CPU_FLUSH);
// clflush should always be available on x86_64
// if not we are in real trouble because we rely on it
// to flush the code cache.
assert ((result & CPU_FLUSH) != 0, "clflush should be available");
assert (vm_features.supports_feature(CPU_FLUSH), "clflush should be available");
if (std_cpuid1_edx.bits.fxsr != 0 || (is_amd_family() &&
ext_cpuid1_edx.bits.fxsr != 0))
result |= CPU_FXSR;
vm_features.set_feature(CPU_FXSR);
// HT flag is set for multi-core processors also.
if (threads_per_core() > 1)
result |= CPU_HT;
vm_features.set_feature(CPU_HT);
if (std_cpuid1_edx.bits.mmx != 0 || (is_amd_family() &&
ext_cpuid1_edx.bits.mmx != 0))
result |= CPU_MMX;
vm_features.set_feature(CPU_MMX);
if (std_cpuid1_edx.bits.sse != 0)
result |= CPU_SSE;
vm_features.set_feature(CPU_SSE);
if (std_cpuid1_edx.bits.sse2 != 0)
result |= CPU_SSE2;
vm_features.set_feature(CPU_SSE2);
if (std_cpuid1_ecx.bits.sse3 != 0)
result |= CPU_SSE3;
vm_features.set_feature(CPU_SSE3);
if (std_cpuid1_ecx.bits.ssse3 != 0)
result |= CPU_SSSE3;
vm_features.set_feature(CPU_SSSE3);
if (std_cpuid1_ecx.bits.sse4_1 != 0)
result |= CPU_SSE4_1;
vm_features.set_feature(CPU_SSE4_1);
if (std_cpuid1_ecx.bits.sse4_2 != 0)
result |= CPU_SSE4_2;
vm_features.set_feature(CPU_SSE4_2);
if (std_cpuid1_ecx.bits.popcnt != 0)
result |= CPU_POPCNT;
vm_features.set_feature(CPU_POPCNT);
if (sefsl1_cpuid7_edx.bits.apx_f != 0 &&
xem_xcr0_eax.bits.apx_f != 0) {
result |= CPU_APX_F;
vm_features.set_feature(CPU_APX_F);
}
if (std_cpuid1_ecx.bits.avx != 0 &&
std_cpuid1_ecx.bits.osxsave != 0 &&
xem_xcr0_eax.bits.sse != 0 &&
xem_xcr0_eax.bits.ymm != 0) {
result |= CPU_AVX;
result |= CPU_VZEROUPPER;
vm_features.set_feature(CPU_AVX);
vm_features.set_feature(CPU_VZEROUPPER);
if (sefsl1_cpuid7_eax.bits.sha512 != 0)
result |= CPU_SHA512;
vm_features.set_feature(CPU_SHA512);
if (std_cpuid1_ecx.bits.f16c != 0)
result |= CPU_F16C;
vm_features.set_feature(CPU_F16C);
if (sef_cpuid7_ebx.bits.avx2 != 0) {
result |= CPU_AVX2;
vm_features.set_feature(CPU_AVX2);
if (sefsl1_cpuid7_eax.bits.avx_ifma != 0)
result |= CPU_AVX_IFMA;
vm_features.set_feature(CPU_AVX_IFMA);
}
if (sef_cpuid7_ecx.bits.gfni != 0)
result |= CPU_GFNI;
vm_features.set_feature(CPU_GFNI);
if (sef_cpuid7_ebx.bits.avx512f != 0 &&
xem_xcr0_eax.bits.opmask != 0 &&
xem_xcr0_eax.bits.zmm512 != 0 &&
xem_xcr0_eax.bits.zmm32 != 0) {
result |= CPU_AVX512F;
vm_features.set_feature(CPU_AVX512F);
if (sef_cpuid7_ebx.bits.avx512cd != 0)
result |= CPU_AVX512CD;
vm_features.set_feature(CPU_AVX512CD);
if (sef_cpuid7_ebx.bits.avx512dq != 0)
result |= CPU_AVX512DQ;
vm_features.set_feature(CPU_AVX512DQ);
if (sef_cpuid7_ebx.bits.avx512ifma != 0)
result |= CPU_AVX512_IFMA;
vm_features.set_feature(CPU_AVX512_IFMA);
if (sef_cpuid7_ebx.bits.avx512pf != 0)
result |= CPU_AVX512PF;
vm_features.set_feature(CPU_AVX512PF);
if (sef_cpuid7_ebx.bits.avx512er != 0)
result |= CPU_AVX512ER;
vm_features.set_feature(CPU_AVX512ER);
if (sef_cpuid7_ebx.bits.avx512bw != 0)
result |= CPU_AVX512BW;
vm_features.set_feature(CPU_AVX512BW);
if (sef_cpuid7_ebx.bits.avx512vl != 0)
result |= CPU_AVX512VL;
vm_features.set_feature(CPU_AVX512VL);
if (sef_cpuid7_ecx.bits.avx512_vpopcntdq != 0)
result |= CPU_AVX512_VPOPCNTDQ;
vm_features.set_feature(CPU_AVX512_VPOPCNTDQ);
if (sef_cpuid7_ecx.bits.avx512_vpclmulqdq != 0)
result |= CPU_AVX512_VPCLMULQDQ;
vm_features.set_feature(CPU_AVX512_VPCLMULQDQ);
if (sef_cpuid7_ecx.bits.vaes != 0)
result |= CPU_AVX512_VAES;
vm_features.set_feature(CPU_AVX512_VAES);
if (sef_cpuid7_ecx.bits.avx512_vnni != 0)
result |= CPU_AVX512_VNNI;
vm_features.set_feature(CPU_AVX512_VNNI);
if (sef_cpuid7_ecx.bits.avx512_bitalg != 0)
result |= CPU_AVX512_BITALG;
vm_features.set_feature(CPU_AVX512_BITALG);
if (sef_cpuid7_ecx.bits.avx512_vbmi != 0)
result |= CPU_AVX512_VBMI;
vm_features.set_feature(CPU_AVX512_VBMI);
if (sef_cpuid7_ecx.bits.avx512_vbmi2 != 0)
result |= CPU_AVX512_VBMI2;
vm_features.set_feature(CPU_AVX512_VBMI2);
}
if (is_intel()) {
if (sefsl1_cpuid7_edx.bits.avx10 != 0 &&
std_cpuid24_ebx.bits.avx10_vlen_512 !=0 &&
std_cpuid24_ebx.bits.avx10_converged_isa_version >= 1 &&
xem_xcr0_eax.bits.opmask != 0 &&
xem_xcr0_eax.bits.zmm512 != 0 &&
xem_xcr0_eax.bits.zmm32 != 0) {
vm_features.set_feature(CPU_AVX10_1);
vm_features.set_feature(CPU_AVX512F);
vm_features.set_feature(CPU_AVX512CD);
vm_features.set_feature(CPU_AVX512DQ);
vm_features.set_feature(CPU_AVX512PF);
vm_features.set_feature(CPU_AVX512ER);
vm_features.set_feature(CPU_AVX512BW);
vm_features.set_feature(CPU_AVX512VL);
vm_features.set_feature(CPU_AVX512_VPOPCNTDQ);
vm_features.set_feature(CPU_AVX512_VPCLMULQDQ);
vm_features.set_feature(CPU_AVX512_VAES);
vm_features.set_feature(CPU_AVX512_VNNI);
vm_features.set_feature(CPU_AVX512_BITALG);
vm_features.set_feature(CPU_AVX512_VBMI);
vm_features.set_feature(CPU_AVX512_VBMI2);
if (std_cpuid24_ebx.bits.avx10_converged_isa_version >= 2) {
vm_features.set_feature(CPU_AVX10_2);
}
}
}
}
if (std_cpuid1_ecx.bits.hv != 0)
result |= CPU_HV;
vm_features.set_feature(CPU_HV);
if (sef_cpuid7_ebx.bits.bmi1 != 0)
result |= CPU_BMI1;
vm_features.set_feature(CPU_BMI1);
if (std_cpuid1_edx.bits.tsc != 0)
result |= CPU_TSC;
vm_features.set_feature(CPU_TSC);
if (ext_cpuid7_edx.bits.tsc_invariance != 0)
result |= CPU_TSCINV_BIT;
vm_features.set_feature(CPU_TSCINV_BIT);
if (std_cpuid1_ecx.bits.aes != 0)
result |= CPU_AES;
vm_features.set_feature(CPU_AES);
if (ext_cpuid1_ecx.bits.lzcnt != 0)
result |= CPU_LZCNT;
vm_features.set_feature(CPU_LZCNT);
if (ext_cpuid1_ecx.bits.prefetchw != 0)
result |= CPU_3DNOW_PREFETCH;
vm_features.set_feature(CPU_3DNOW_PREFETCH);
if (sef_cpuid7_ebx.bits.erms != 0)
result |= CPU_ERMS;
vm_features.set_feature(CPU_ERMS);
if (sef_cpuid7_edx.bits.fast_short_rep_mov != 0)
result |= CPU_FSRM;
vm_features.set_feature(CPU_FSRM);
if (std_cpuid1_ecx.bits.clmul != 0)
result |= CPU_CLMUL;
vm_features.set_feature(CPU_CLMUL);
if (sef_cpuid7_ebx.bits.rtm != 0)
result |= CPU_RTM;
vm_features.set_feature(CPU_RTM);
if (sef_cpuid7_ebx.bits.adx != 0)
result |= CPU_ADX;
vm_features.set_feature(CPU_ADX);
if (sef_cpuid7_ebx.bits.bmi2 != 0)
result |= CPU_BMI2;
vm_features.set_feature(CPU_BMI2);
if (sef_cpuid7_ebx.bits.sha != 0)
result |= CPU_SHA;
vm_features.set_feature(CPU_SHA);
if (std_cpuid1_ecx.bits.fma != 0)
result |= CPU_FMA;
vm_features.set_feature(CPU_FMA);
if (sef_cpuid7_ebx.bits.clflushopt != 0)
result |= CPU_FLUSHOPT;
vm_features.set_feature(CPU_FLUSHOPT);
if (sef_cpuid7_ebx.bits.clwb != 0)
result |= CPU_CLWB;
vm_features.set_feature(CPU_CLWB);
if (ext_cpuid1_edx.bits.rdtscp != 0)
result |= CPU_RDTSCP;
vm_features.set_feature(CPU_RDTSCP);
if (sef_cpuid7_ecx.bits.rdpid != 0)
result |= CPU_RDPID;
vm_features.set_feature(CPU_RDPID);
// AMD|Hygon additional features.
if (is_amd_family()) {
// PREFETCHW was checked above, check TDNOW here.
if ((ext_cpuid1_edx.bits.tdnow != 0))
result |= CPU_3DNOW_PREFETCH;
vm_features.set_feature(CPU_3DNOW_PREFETCH);
if (ext_cpuid1_ecx.bits.sse4a != 0)
result |= CPU_SSE4A;
vm_features.set_feature(CPU_SSE4A);
}
// Intel additional features.
if (is_intel()) {
if (sef_cpuid7_edx.bits.serialize != 0)
result |= CPU_SERIALIZE;
vm_features.set_feature(CPU_SERIALIZE);
if (_cpuid_info.sef_cpuid7_edx.bits.avx512_fp16 != 0)
result |= CPU_AVX512_FP16;
vm_features.set_feature(CPU_AVX512_FP16);
}
// ZX additional features.
if (is_zx()) {
// We do not know if these are supported by ZX, so we cannot trust
// common CPUID bit for them.
assert((result & CPU_CLWB) == 0, "Check if it is supported?");
result &= ~CPU_CLWB;
assert(vm_features.supports_feature(CPU_CLWB), "Check if it is supported?");
vm_features.clear_feature(CPU_CLWB);
}
// Protection key features.
if (sef_cpuid7_ecx.bits.pku != 0) {
result |= CPU_PKU;
vm_features.set_feature(CPU_PKU);
}
if (sef_cpuid7_ecx.bits.ospke != 0) {
result |= CPU_OSPKE;
vm_features.set_feature(CPU_OSPKE);
}
// Control flow enforcement (CET) features.
if (sef_cpuid7_ecx.bits.cet_ss != 0) {
result |= CPU_CET_SS;
vm_features.set_feature(CPU_CET_SS);
}
if (sef_cpuid7_edx.bits.cet_ibt != 0) {
result |= CPU_CET_IBT;
vm_features.set_feature(CPU_CET_IBT);
}
// Composite features.
if (supports_tscinv_bit() &&
((is_amd_family() && !is_amd_Barcelona()) ||
is_intel_tsc_synched_at_init())) {
result |= CPU_TSCINV;
vm_features.set_feature(CPU_TSCINV);
}
return result;
return vm_features;
}
bool VM_Version::os_supports_avx_vectors() {
@ -3231,3 +3281,14 @@ bool VM_Version::is_intrinsic_supported(vmIntrinsicID id) {
}
return true;
}
void VM_Version::insert_features_names(VM_Version::VM_Features features, char* buf, size_t buflen) {
for (int i = 0; i < MAX_CPU_FEATURES; i++) {
if (features.supports_feature((VM_Version::Feature_Flag)i)) {
int res = jio_snprintf(buf, buflen, ", %s", _features_names[i]);
assert(res > 0, "not enough temporary space allocated");
buf += res;
buflen -= res;
}
}
}

View File

@ -295,12 +295,32 @@ class VM_Version : public Abstract_VM_Version {
union SefCpuid7SubLeaf1Edx {
uint32_t value;
struct {
uint32_t : 21,
uint32_t : 19,
avx10 : 1,
: 1,
apx_f : 1,
: 10;
} bits;
};
union StdCpuid24MainLeafEax {
uint32_t value;
struct {
uint32_t sub_leaves_cnt : 31;
} bits;
};
union StdCpuid24MainLeafEbx {
uint32_t value;
struct {
uint32_t avx10_converged_isa_version : 8,
: 8,
: 2,
avx10_vlen_512 : 1,
: 13;
} bits;
};
union ExtCpuid1EEbx {
uint32_t value;
struct {
@ -342,9 +362,9 @@ protected:
/*
* Update following files when declaring new flags:
* test/lib-test/jdk/test/whitebox/CPUInfoTest.java
* src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.amd64/src/jdk/vm/ci/amd64/AMD64.java
* src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/amd64/AMD64.java
*/
enum Feature_Flag : uint64_t {
enum Feature_Flag {
#define CPU_FEATURE_FLAGS(decl) \
decl(CX8, "cx8", 0) /* next bits are from cpuid 1 (EDX) */ \
decl(CMOV, "cmov", 1) \
@ -420,15 +440,85 @@ protected:
decl(AVX_IFMA, "avx_ifma", 59) /* 256-bit VEX-coded variant of AVX512-IFMA*/ \
decl(APX_F, "apx_f", 60) /* Intel Advanced Performance Extensions*/ \
decl(SHA512, "sha512", 61) /* SHA512 instructions*/ \
decl(AVX512_FP16, "avx512_fp16", 62) /* AVX512 FP16 ISA support*/
decl(AVX512_FP16, "avx512_fp16", 62) /* AVX512 FP16 ISA support*/ \
decl(AVX10_1, "avx10_1", 63) /* AVX10 512 bit vector ISA Version 1 support*/ \
decl(AVX10_2, "avx10_2", 64) /* AVX10 512 bit vector ISA Version 2 support*/
#define DECLARE_CPU_FEATURE_FLAG(id, name, bit) CPU_##id = (1ULL << bit),
#define DECLARE_CPU_FEATURE_FLAG(id, name, bit) CPU_##id = (bit),
CPU_FEATURE_FLAGS(DECLARE_CPU_FEATURE_FLAG)
#undef DECLARE_CPU_FEATURE_FLAG
MAX_CPU_FEATURES
};
class VM_Features {
friend class VMStructs;
friend class JVMCIVMStructs;
private:
uint64_t _features_bitmap[(MAX_CPU_FEATURES / BitsPerLong) + 1];
STATIC_ASSERT(sizeof(_features_bitmap) * BitsPerByte >= MAX_CPU_FEATURES);
// Number of 8-byte elements in _bitmap.
constexpr static int features_bitmap_element_count() {
return sizeof(_features_bitmap) / sizeof(uint64_t);
}
constexpr static int features_bitmap_element_shift_count() {
return LogBitsPerLong;
}
constexpr static uint64_t features_bitmap_element_mask() {
return (1ULL << features_bitmap_element_shift_count()) - 1;
}
static int index(Feature_Flag feature) {
int idx = feature >> features_bitmap_element_shift_count();
assert(idx < features_bitmap_element_count(), "Features array index out of bounds");
return idx;
}
static uint64_t bit_mask(Feature_Flag feature) {
return (1ULL << (feature & features_bitmap_element_mask()));
}
static int _features_bitmap_size; // for JVMCI purposes
public:
VM_Features() {
for (int i = 0; i < features_bitmap_element_count(); i++) {
_features_bitmap[i] = 0;
}
}
void set_feature(Feature_Flag feature) {
int idx = index(feature);
_features_bitmap[idx] |= bit_mask(feature);
}
void clear_feature(VM_Version::Feature_Flag feature) {
int idx = index(feature);
_features_bitmap[idx] &= ~bit_mask(feature);
}
bool supports_feature(VM_Version::Feature_Flag feature) {
int idx = index(feature);
return (_features_bitmap[idx] & bit_mask(feature)) != 0;
}
};
// CPU feature flags vector, can be affected by VM settings.
static VM_Features _features;
// Original CPU feature flags vector, not affected by VM settings.
static VM_Features _cpu_features;
static const char* _features_names[];
static void clear_cpu_features() {
_features = VM_Features();
_cpu_features = VM_Features();
}
enum Extended_Family {
// AMD
CPU_FAMILY_AMD_11H = 0x11,
@ -492,6 +582,11 @@ protected:
SefCpuid7SubLeaf1Eax sefsl1_cpuid7_eax;
SefCpuid7SubLeaf1Edx sefsl1_cpuid7_edx;
// cpuid function 24 converged vector ISA main leaf
// eax = 24, ecx = 0
StdCpuid24MainLeafEax std_cpuid24_eax;
StdCpuid24MainLeafEbx std_cpuid24_ebx;
// cpuid function 0xB (processor topology)
// ecx = 0
uint32_t tpl_cpuidB0_eax;
@ -565,7 +660,7 @@ protected:
// Space to save apx registers after signal handle
jlong apx_save[2]; // Save r16 and r31
uint64_t feature_flags() const;
VM_Features feature_flags() const;
// Asserts
void assert_is_initialized() const {
@ -611,6 +706,7 @@ public:
// Offsets for cpuid asm stub
static ByteSize std_cpuid0_offset() { return byte_offset_of(CpuidInfo, std_max_function); }
static ByteSize std_cpuid1_offset() { return byte_offset_of(CpuidInfo, std_cpuid1_eax); }
static ByteSize std_cpuid24_offset() { return byte_offset_of(CpuidInfo, std_cpuid24_eax); }
static ByteSize dcp_cpuid4_offset() { return byte_offset_of(CpuidInfo, dcp_cpuid4_eax); }
static ByteSize sef_cpuid7_offset() { return byte_offset_of(CpuidInfo, sef_cpuid7_eax); }
static ByteSize sefsl1_cpuid7_offset() { return byte_offset_of(CpuidInfo, sefsl1_cpuid7_eax); }
@ -644,11 +740,29 @@ public:
static void clear_apx_test_state();
static void clean_cpuFeatures() { _features = 0; }
static void set_avx_cpuFeatures() { _features |= (CPU_SSE | CPU_SSE2 | CPU_AVX | CPU_VZEROUPPER ); }
static void set_evex_cpuFeatures() { _features |= (CPU_AVX512F | CPU_SSE | CPU_SSE2 | CPU_VZEROUPPER ); }
static void set_apx_cpuFeatures() { _features |= CPU_APX_F; }
static void set_bmi_cpuFeatures() { _features |= (CPU_BMI1 | CPU_BMI2 | CPU_LZCNT | CPU_POPCNT); }
static void clean_cpuFeatures() {
VM_Version::clear_cpu_features();
}
static void set_avx_cpuFeatures() {
_features.set_feature(CPU_SSE);
_features.set_feature(CPU_SSE2);
_features.set_feature(CPU_AVX);
_features.set_feature(CPU_VZEROUPPER);
}
static void set_evex_cpuFeatures() {
_features.set_feature(CPU_AVX10_1);
_features.set_feature(CPU_AVX512F);
_features.set_feature(CPU_SSE);
_features.set_feature(CPU_SSE2);
_features.set_feature(CPU_VZEROUPPER);
}
static void set_apx_cpuFeatures() { _features.set_feature(CPU_APX_F); }
static void set_bmi_cpuFeatures() {
_features.set_feature(CPU_BMI1);
_features.set_feature(CPU_BMI2);
_features.set_feature(CPU_LZCNT);
_features.set_feature(CPU_POPCNT);
}
// Initialization
static void initialize();
@ -703,40 +817,39 @@ public:
//
// Feature identification which can be affected by VM settings
//
static bool supports_cpuid() { return _features != 0; }
static bool supports_cmov() { return (_features & CPU_CMOV) != 0; }
static bool supports_fxsr() { return (_features & CPU_FXSR) != 0; }
static bool supports_ht() { return (_features & CPU_HT) != 0; }
static bool supports_mmx() { return (_features & CPU_MMX) != 0; }
static bool supports_sse() { return (_features & CPU_SSE) != 0; }
static bool supports_sse2() { return (_features & CPU_SSE2) != 0; }
static bool supports_sse3() { return (_features & CPU_SSE3) != 0; }
static bool supports_ssse3() { return (_features & CPU_SSSE3)!= 0; }
static bool supports_sse4_1() { return (_features & CPU_SSE4_1) != 0; }
static bool supports_sse4_2() { return (_features & CPU_SSE4_2) != 0; }
static bool supports_popcnt() { return (_features & CPU_POPCNT) != 0; }
static bool supports_avx() { return (_features & CPU_AVX) != 0; }
static bool supports_avx2() { return (_features & CPU_AVX2) != 0; }
static bool supports_tsc() { return (_features & CPU_TSC) != 0; }
static bool supports_rdtscp() { return (_features & CPU_RDTSCP) != 0; }
static bool supports_rdpid() { return (_features & CPU_RDPID) != 0; }
static bool supports_aes() { return (_features & CPU_AES) != 0; }
static bool supports_erms() { return (_features & CPU_ERMS) != 0; }
static bool supports_fsrm() { return (_features & CPU_FSRM) != 0; }
static bool supports_clmul() { return (_features & CPU_CLMUL) != 0; }
static bool supports_rtm() { return (_features & CPU_RTM) != 0; }
static bool supports_bmi1() { return (_features & CPU_BMI1) != 0; }
static bool supports_bmi2() { return (_features & CPU_BMI2) != 0; }
static bool supports_adx() { return (_features & CPU_ADX) != 0; }
static bool supports_evex() { return (_features & CPU_AVX512F) != 0; }
static bool supports_avx512dq() { return (_features & CPU_AVX512DQ) != 0; }
static bool supports_avx512ifma() { return (_features & CPU_AVX512_IFMA) != 0; }
static bool supports_avxifma() { return (_features & CPU_AVX_IFMA) != 0; }
static bool supports_avx512pf() { return (_features & CPU_AVX512PF) != 0; }
static bool supports_avx512er() { return (_features & CPU_AVX512ER) != 0; }
static bool supports_avx512cd() { return (_features & CPU_AVX512CD) != 0; }
static bool supports_avx512bw() { return (_features & CPU_AVX512BW) != 0; }
static bool supports_avx512vl() { return (_features & CPU_AVX512VL) != 0; }
static bool supports_cmov() { return _features.supports_feature(CPU_CMOV); }
static bool supports_fxsr() { return _features.supports_feature(CPU_FXSR); }
static bool supports_ht() { return _features.supports_feature(CPU_HT); }
static bool supports_mmx() { return _features.supports_feature(CPU_MMX); }
static bool supports_sse() { return _features.supports_feature(CPU_SSE); }
static bool supports_sse2() { return _features.supports_feature(CPU_SSE2); }
static bool supports_sse3() { return _features.supports_feature(CPU_SSE3); }
static bool supports_ssse3() { return _features.supports_feature(CPU_SSSE3); }
static bool supports_sse4_1() { return _features.supports_feature(CPU_SSE4_1); }
static bool supports_sse4_2() { return _features.supports_feature(CPU_SSE4_2); }
static bool supports_popcnt() { return _features.supports_feature(CPU_POPCNT); }
static bool supports_avx() { return _features.supports_feature(CPU_AVX); }
static bool supports_avx2() { return _features.supports_feature(CPU_AVX2); }
static bool supports_tsc() { return _features.supports_feature(CPU_TSC); }
static bool supports_rdtscp() { return _features.supports_feature(CPU_RDTSCP); }
static bool supports_rdpid() { return _features.supports_feature(CPU_RDPID); }
static bool supports_aes() { return _features.supports_feature(CPU_AES); }
static bool supports_erms() { return _features.supports_feature(CPU_ERMS); }
static bool supports_fsrm() { return _features.supports_feature(CPU_FSRM); }
static bool supports_clmul() { return _features.supports_feature(CPU_CLMUL); }
static bool supports_rtm() { return _features.supports_feature(CPU_RTM); }
static bool supports_bmi1() { return _features.supports_feature(CPU_BMI1); }
static bool supports_bmi2() { return _features.supports_feature(CPU_BMI2); }
static bool supports_adx() { return _features.supports_feature(CPU_ADX); }
static bool supports_evex() { return _features.supports_feature(CPU_AVX512F); }
static bool supports_avx512dq() { return _features.supports_feature(CPU_AVX512DQ); }
static bool supports_avx512ifma() { return _features.supports_feature(CPU_AVX512_IFMA); }
static bool supports_avxifma() { return _features.supports_feature(CPU_AVX_IFMA); }
static bool supports_avx512pf() { return _features.supports_feature(CPU_AVX512PF); }
static bool supports_avx512er() { return _features.supports_feature(CPU_AVX512ER); }
static bool supports_avx512cd() { return _features.supports_feature(CPU_AVX512CD); }
static bool supports_avx512bw() { return _features.supports_feature(CPU_AVX512BW); }
static bool supports_avx512vl() { return _features.supports_feature(CPU_AVX512VL); }
static bool supports_avx512vlbw() { return (supports_evex() && supports_avx512bw() && supports_avx512vl()); }
static bool supports_avx512bwdq() { return (supports_evex() && supports_avx512bw() && supports_avx512dq()); }
static bool supports_avx512vldq() { return (supports_evex() && supports_avx512dq() && supports_avx512vl()); }
@ -745,33 +858,39 @@ public:
static bool supports_avx512novl() { return (supports_evex() && !supports_avx512vl()); }
static bool supports_avx512nobw() { return (supports_evex() && !supports_avx512bw()); }
static bool supports_avx256only() { return (supports_avx2() && !supports_evex()); }
static bool supports_apx_f() { return (_features & CPU_APX_F) != 0; }
static bool supports_apx_f() { return _features.supports_feature(CPU_APX_F); }
static bool supports_avxonly() { return ((supports_avx2() || supports_avx()) && !supports_evex()); }
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_avx512_vpopcntdq() { return (_features & CPU_AVX512_VPOPCNTDQ) != 0; }
static bool supports_avx512_vpclmulqdq() { return (_features & CPU_AVX512_VPCLMULQDQ) != 0; }
static bool supports_avx512_vaes() { return (_features & CPU_AVX512_VAES) != 0; }
static bool supports_gfni() { return (_features & CPU_GFNI) != 0; }
static bool supports_avx512_vnni() { return (_features & CPU_AVX512_VNNI) != 0; }
static bool supports_avx512_bitalg() { return (_features & CPU_AVX512_BITALG) != 0; }
static bool supports_avx512_vbmi() { return (_features & CPU_AVX512_VBMI) != 0; }
static bool supports_avx512_vbmi2() { return (_features & CPU_AVX512_VBMI2) != 0; }
static bool supports_avx512_fp16() { return (_features & CPU_AVX512_FP16) != 0; }
static bool supports_hv() { return (_features & CPU_HV) != 0; }
static bool supports_serialize() { return (_features & CPU_SERIALIZE) != 0; }
static bool supports_f16c() { return (_features & CPU_F16C) != 0; }
static bool supports_pku() { return (_features & CPU_PKU) != 0; }
static bool supports_ospke() { return (_features & CPU_OSPKE) != 0; }
static bool supports_cet_ss() { return (_features & CPU_CET_SS) != 0; }
static bool supports_cet_ibt() { return (_features & CPU_CET_IBT) != 0; }
static bool supports_sha512() { return (_features & CPU_SHA512) != 0; }
static bool supports_sha() { return _features.supports_feature(CPU_SHA); }
static bool supports_fma() { return _features.supports_feature(CPU_FMA) && supports_avx(); }
static bool supports_vzeroupper() { return _features.supports_feature(CPU_VZEROUPPER); }
static bool supports_avx512_vpopcntdq() { return _features.supports_feature(CPU_AVX512_VPOPCNTDQ); }
static bool supports_avx512_vpclmulqdq() { return _features.supports_feature(CPU_AVX512_VPCLMULQDQ); }
static bool supports_avx512_vaes() { return _features.supports_feature(CPU_AVX512_VAES); }
static bool supports_gfni() { return _features.supports_feature(CPU_GFNI); }
static bool supports_avx512_vnni() { return _features.supports_feature(CPU_AVX512_VNNI); }
static bool supports_avx512_bitalg() { return _features.supports_feature(CPU_AVX512_BITALG); }
static bool supports_avx512_vbmi() { return _features.supports_feature(CPU_AVX512_VBMI); }
static bool supports_avx512_vbmi2() { return _features.supports_feature(CPU_AVX512_VBMI2); }
static bool supports_avx512_fp16() { return _features.supports_feature(CPU_AVX512_FP16); }
static bool supports_hv() { return _features.supports_feature(CPU_HV); }
static bool supports_serialize() { return _features.supports_feature(CPU_SERIALIZE); }
static bool supports_f16c() { return _features.supports_feature(CPU_F16C); }
static bool supports_pku() { return _features.supports_feature(CPU_PKU); }
static bool supports_ospke() { return _features.supports_feature(CPU_OSPKE); }
static bool supports_cet_ss() { return _features.supports_feature(CPU_CET_SS); }
static bool supports_cet_ibt() { return _features.supports_feature(CPU_CET_IBT); }
static bool supports_sha512() { return _features.supports_feature(CPU_SHA512); }
// Intel® AVX10 introduces a versioned approach for enumeration that is monotonically increasing, inclusive,
// and supporting all vector lengths. Feature set supported by an AVX10 vector ISA version is also supported
// by all the versions above it.
static bool supports_avx10_1() { return _features.supports_feature(CPU_AVX10_1);}
static bool supports_avx10_2() { return _features.supports_feature(CPU_AVX10_2);}
//
// Feature identification not affected by VM flags
//
static bool cpu_supports_evex() { return (_cpu_features & CPU_AVX512F) != 0; }
static bool cpu_supports_evex() { return _cpu_features.supports_feature(CPU_AVX512F); }
static bool supports_avx512_simd_sort() {
if (supports_avx512dq()) {
@ -802,6 +921,8 @@ public:
static bool is_intel_tsc_synched_at_init();
static void insert_features_names(VM_Version::VM_Features features, char* buf, size_t buflen);
// This checks if the JVM is potentially affected by an erratum on Intel CPUs (SKX102)
// that causes unpredictable behaviour when jcc crosses 64 byte boundaries. Its microcode
// mitigation causes regressions when jumps or fused conditional branches cross or end at
@ -809,19 +930,19 @@ public:
static bool has_intel_jcc_erratum() { return _has_intel_jcc_erratum; }
// AMD features
static bool supports_3dnow_prefetch() { return (_features & CPU_3DNOW_PREFETCH) != 0; }
static bool supports_lzcnt() { return (_features & CPU_LZCNT) != 0; }
static bool supports_sse4a() { return (_features & CPU_SSE4A) != 0; }
static bool supports_3dnow_prefetch() { return _features.supports_feature(CPU_3DNOW_PREFETCH); }
static bool supports_lzcnt() { return _features.supports_feature(CPU_LZCNT); }
static bool supports_sse4a() { return _features.supports_feature(CPU_SSE4A); }
static bool is_amd_Barcelona() { return is_amd() &&
extended_cpu_family() == CPU_FAMILY_AMD_11H; }
// Intel and AMD newer cores support fast timestamps well
static bool supports_tscinv_bit() {
return (_features & CPU_TSCINV_BIT) != 0;
return _features.supports_feature(CPU_TSCINV_BIT);
}
static bool supports_tscinv() {
return (_features & CPU_TSCINV) != 0;
return _features.supports_feature(CPU_TSCINV);
}
// Intel Core and newer cpus have fast IDIV instruction (excluding Atom).
@ -882,8 +1003,8 @@ public:
static bool supports_clflush(); // Can't inline due to header file conflict
// Note: CPU_FLUSHOPT and CPU_CLWB bits should always be zero for 32-bit
static bool supports_clflushopt() { return ((_features & CPU_FLUSHOPT) != 0); }
static bool supports_clwb() { return ((_features & CPU_CLWB) != 0); }
static bool supports_clflushopt() { return (_features.supports_feature(CPU_FLUSHOPT)); }
static bool supports_clwb() { return (_features.supports_feature(CPU_CLWB)); }
// Old CPUs perform lea on AGU which causes additional latency transferring the
// value from/to ALU for other operations

View File

@ -470,6 +470,7 @@ jobjectArray readConfiguration0(JNIEnv *env, JVMCI_TRAPS) {
strcmp(vmField.typeString, "intptr_t") == 0 ||
strcmp(vmField.typeString, "uintptr_t") == 0 ||
strcmp(vmField.typeString, "OopHandle") == 0 ||
strcmp(vmField.typeString, "VM_Version::VM_Features") == 0 ||
strcmp(vmField.typeString, "size_t") == 0 ||
// All foo* types are addresses.
vmField.typeString[strlen(vmField.typeString) - 1] == '*') {

View File

@ -150,7 +150,7 @@
\
static_field(CompilerToVM::Data, data_section_item_alignment, int) \
\
JVMTI_ONLY(static_field(CompilerToVM::Data, _should_notify_object_alloc, int*)) \
JVMTI_ONLY(static_field(CompilerToVM::Data, _should_notify_object_alloc, int*)) \
\
static_field(Abstract_VM_Version, _features, uint64_t) \
\
@ -997,7 +997,11 @@
#define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field) \
volatile_nonstatic_field(JavaFrameAnchor, _last_Java_fp, intptr_t*) \
static_field(VM_Version, _has_intel_jcc_erratum, bool)
static_field(VM_Version, _features, VM_Version::VM_Features) \
\
nonstatic_field(VM_Version::VM_Features, _features_bitmap[0], uint64_t) \
static_field(VM_Version::VM_Features, _features_bitmap_size, int) \
static_field(VM_Version, _has_intel_jcc_erratum, bool)
#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant) \
LP64_ONLY(declare_constant(frame::arg_reg_save_area_bytes)) \
@ -1005,7 +1009,8 @@
declare_constant(frame::interpreter_frame_last_sp_offset)
#define DECLARE_LONG_CPU_FEATURE_CONSTANT(id, name, bit) GENERATE_VM_LONG_CONSTANT_ENTRY(VM_Version::CPU_##id)
#define VM_LONG_CPU_FEATURE_CONSTANTS CPU_FEATURE_FLAGS(DECLARE_LONG_CPU_FEATURE_CONSTANT)
#define VM_LONG_CPU_FEATURE_CONSTANTS \
CPU_FEATURE_FLAGS(DECLARE_LONG_CPU_FEATURE_CONSTANT)
#endif

View File

@ -325,22 +325,6 @@ unsigned int Abstract_VM_Version::jvm_version() {
(Abstract_VM_Version::vm_build_number() & 0xFF);
}
void Abstract_VM_Version::insert_features_names(char* buf, size_t buflen, const char* features_names[]) {
uint64_t features = _features;
uint features_names_index = 0;
while (features != 0) {
if (features & 1) {
int res = jio_snprintf(buf, buflen, ", %s", features_names[features_names_index]);
assert(res > 0, "not enough temporary space allocated");
buf += res;
buflen -= res;
}
features >>= 1;
++features_names_index;
}
}
const char* Abstract_VM_Version::extract_features_string(const char* cpu_info_string,
size_t cpu_info_string_len,
size_t features_offset) {

View File

@ -56,6 +56,7 @@ class Abstract_VM_Version: AllStatic {
// CPU feature flags, can be affected by VM settings.
static uint64_t _features;
static const char* _features_string;
static const char* _cpu_info_string;
@ -128,10 +129,9 @@ class Abstract_VM_Version: AllStatic {
static const char* jdk_debug_level();
static const char* printable_jdk_debug_level();
static uint64_t features() { return _features; }
static const char* features_string() { return _features_string; }
static const char* cpu_info_string() { return _cpu_info_string; }
static void insert_features_names(char* buf, size_t buflen, const char* features_names[]);
static const char* extract_features_string(const char* cpu_info_string,
size_t cpu_info_string_len,
size_t features_offset);

View File

@ -1,3 +1,4 @@
/*
* Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@ -1164,6 +1165,7 @@
/********************/ \
\
declare_toplevel_type(Abstract_VM_Version) \
declare_toplevel_type(VM_Version) \
\
/*************/ \
/* Arguments */ \
@ -1716,7 +1718,6 @@
/**********************/ \
NOT_ZERO(PPC64_ONLY(declare_constant(frame::entry_frame_locals_size))) \
\
NOT_ZERO(X86_ONLY(declare_constant(frame::entry_frame_call_wrapper_offset))) \
declare_constant(frame::pc_return_offset) \
\
/*************/ \
@ -2146,3 +2147,4 @@ void vmStructs_init() {
VMStructs::init();
}
#endif // ASSERT

View File

@ -258,6 +258,8 @@ public class AMD64 extends Architecture {
APX_F,
SHA512,
AVX512_FP16,
AVX10_1,
AVX10_2
}
private final EnumSet<CPUFeature> features;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2025, 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
@ -30,6 +30,7 @@ import java.util.Map.Entry;
import jdk.vm.ci.common.JVMCIError;
import jdk.vm.ci.runtime.JVMCIBackend;
import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE;
public interface HotSpotJVMCIBackendFactory {
@ -80,4 +81,58 @@ public interface HotSpotJVMCIBackendFactory {
}
return outFeatures;
}
/**
* Converts CPU features bit map into enum constants.
*
* @param <CPUFeatureType> CPU feature enum type
* @param enumType the class of {@code CPUFeatureType}
* @param constants VM constants. Each entry whose key starts with {@code "VM_Version::CPU_"}
* specifies a CPU feature and its value is a mask for a bit in {@code features}
* @param featuresBitMapAddress pointer to {@code VM_Features::_features_bitmap} field of {@code VM_Version::_features}
* @param featuresBitMapSize size of feature bit map in bytes
* @param renaming maps from VM feature names to enum constant names where the two differ
* @throws IllegalArgumentException if any VM CPU feature constant cannot be converted to an
* enum value
* @return the set of converted values
*/
static <CPUFeatureType extends Enum<CPUFeatureType>> EnumSet<CPUFeatureType> convertFeatures(
Class<CPUFeatureType> enumType,
Map<String, Long> constants,
long featuresBitMapAddress,
long featuresBitMapSize,
Map<String, String> renaming) {
EnumSet<CPUFeatureType> outFeatures = EnumSet.noneOf(enumType);
List<String> missing = new ArrayList<>();
for (Entry<String, Long> e : constants.entrySet()) {
String key = e.getKey();
long bitIndex = e.getValue();
if (key.startsWith("VM_Version::CPU_")) {
String name = key.substring("VM_Version::CPU_".length());
try {
final long featuresElementShiftCount = 6; // log (# of bits per long)
final long featuresElementMask = (1L << featuresElementShiftCount) - 1;
CPUFeatureType feature = Enum.valueOf(enumType, renaming.getOrDefault(name, name));
long featureIndex = bitIndex >>> featuresElementShiftCount;
long featureBitMask = 1L << (bitIndex & featuresElementMask);
assert featureIndex < featuresBitMapSize;
long featuresElement = UNSAFE.getLong(featuresBitMapAddress + featureIndex * Long.BYTES);
if ((featuresElement & featureBitMask) != 0) {
outFeatures.add(feature);
}
} catch (IllegalArgumentException iae) {
missing.add(name);
}
}
}
if (!missing.isEmpty()) {
throw new JVMCIError("Missing CPU feature constants: %s", missing);
}
return outFeatures;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2025, 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
@ -50,7 +50,12 @@ public class AMD64HotSpotJVMCIBackendFactory implements HotSpotJVMCIBackendFacto
Map<String, Long> constants = config.getStore().getConstants();
Map<String, String> renaming = Map.of("3DNOW_PREFETCH", "AMD_3DNOW_PREFETCH");
assert config.useSSE >= 2 : "minimum config for x64";
EnumSet<CPUFeature> features = HotSpotJVMCIBackendFactory.convertFeatures(CPUFeature.class, constants, config.vmVersionFeatures, renaming);
long featuresBitMapAddress = config.vmVersionFeatures + config.vmFeaturesFeaturesOffset;
EnumSet<CPUFeature> features = HotSpotJVMCIBackendFactory.convertFeatures(CPUFeature.class,
constants,
featuresBitMapAddress,
config.vmFeaturesFeaturesSize,
renaming);
features.add(AMD64.CPUFeature.SSE);
features.add(AMD64.CPUFeature.SSE2);
return features;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2025, 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
@ -42,12 +42,14 @@ class AMD64HotSpotVMConfig extends HotSpotVMConfigAccess {
final boolean useCountTrailingZerosInstruction = getFlag("UseCountTrailingZerosInstruction", Boolean.class);
final boolean useCompressedOops = getFlag("UseCompressedOops", Boolean.class);
final long vmVersionFeatures = getFieldAddress("VM_Version::_features", "VM_Version::VM_Features");
final long vmFeaturesFeaturesOffset = getFieldOffset("VM_Version::VM_Features::_features_bitmap[0]", Long.class, "uint64_t");
final long vmFeaturesFeaturesSize = getFieldValue("VM_Version::VM_Features::_features_bitmap_size", Long.class, "int");
// CPU capabilities
final int useSSE = getFlag("UseSSE", Integer.class);
final int useAVX = getFlag("UseAVX", Integer.class);
final long vmVersionFeatures = getFieldValue("Abstract_VM_Version::_features", Long.class, "uint64_t");
// CPU feature flags
final long amd64CX8 = getConstant("VM_Version::CPU_CX8", Long.class);
final long amd64CMOV = getConstant("VM_Version::CPU_CMOV", Long.class);
@ -88,4 +90,6 @@ class AMD64HotSpotVMConfig extends HotSpotVMConfigAccess {
final long amd64OSPKE = getConstant("VM_Version::CPU_OSPKE", Long.class);
final long amd64CET_IBT = getConstant("VM_Version::CPU_CET_IBT", Long.class);
final long amd64CET_SS = getConstant("VM_Version::CPU_CET_SS", Long.class);
final long amd64AVX10_1 = getConstant("VM_Version::CPU_AVX10_1", Long.class);
final long amd64AVX10_2 = getConstant("VM_Version::CPU_AVX10_2", Long.class);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2025, 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
@ -92,7 +92,7 @@ public class ClhsdbLongConstant {
// Expected output snippet is of the form (on x64-64):
// ...
// longConstant VM_Version::CPU_SHA 17179869184
// longConstant VM_Version::CPU_SHA 34
// longConstant markWord::age_shift 3
// longConstant markWord::hash_mask_in_place 4398046509056
// ...
@ -106,7 +106,7 @@ public class ClhsdbLongConstant {
// Expected value obtained from the CPU_SHA definition in vm_version_x86.hpp
checkLongValue("VM_Version::CPU_SHA ",
longConstantOutput,
17179869184L);
34L);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2025, 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
@ -66,7 +66,7 @@ public class CPUInfoTest {
"hv", "fsrm", "avx512_bitalg", "gfni",
"f16c", "pku", "ospke", "cet_ibt",
"cet_ss", "avx512_ifma", "serialize", "avx_ifma",
"apx_f"
"apx_f", "avx10_1", "avx10_2"
);
// @formatter:on
// Checkstyle: resume