diff --git a/src/hotspot/cpu/aarch64/vmStructs_aarch64.hpp b/src/hotspot/cpu/aarch64/vmStructs_aarch64.hpp index bf9c965213cef..2ec901f6a2ed9 100644 --- a/src/hotspot/cpu/aarch64/vmStructs_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/vmStructs_aarch64.hpp @@ -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) diff --git a/src/hotspot/cpu/x86/vmStructs_x86.hpp b/src/hotspot/cpu/x86/vmStructs_x86.hpp index d894d8b09a7f2..b8089a6413e46 100644 --- a/src/hotspot/cpu/x86/vmStructs_x86.hpp +++ b/src/hotspot/cpu/x86/vmStructs_x86.hpp @@ -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) diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp index 5306f0becefdd..fe59a1534133c 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.cpp +++ b/src/hotspot/cpu/x86/vm_version_x86.cpp @@ -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; + } + } +} diff --git a/src/hotspot/cpu/x86/vm_version_x86.hpp b/src/hotspot/cpu/x86/vm_version_x86.hpp index 7eb627c871417..a544eeb71b8cb 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.hpp +++ b/src/hotspot/cpu/x86/vm_version_x86.hpp @@ -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 @@ class VM_Version : public Abstract_VM_Version { /* * 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 @@ class VM_Version : public Abstract_VM_Version { 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 @@ class VM_Version : public Abstract_VM_Version { 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 @@ class VM_Version : public Abstract_VM_Version { // 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 @@ class VM_Version : public Abstract_VM_Version { // 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 @@ class VM_Version : public Abstract_VM_Version { 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 @@ class VM_Version : public Abstract_VM_Version { // // 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 @@ class VM_Version : public Abstract_VM_Version { 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 @@ class VM_Version : public Abstract_VM_Version { 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 @@ class VM_Version : public Abstract_VM_Version { 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 @@ class VM_Version : public Abstract_VM_Version { 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 diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp index 591f30e7b19d1..532f3333a6d02 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp @@ -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] == '*') { diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index dfc15368cf657..e504ee68f84f0 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -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 diff --git a/src/hotspot/share/runtime/abstract_vm_version.cpp b/src/hotspot/share/runtime/abstract_vm_version.cpp index c0667d739ce7f..5b9d36115f8e9 100644 --- a/src/hotspot/share/runtime/abstract_vm_version.cpp +++ b/src/hotspot/share/runtime/abstract_vm_version.cpp @@ -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) { diff --git a/src/hotspot/share/runtime/abstract_vm_version.hpp b/src/hotspot/share/runtime/abstract_vm_version.hpp index 6f1b886bc9878..4972f02e3d8aa 100644 --- a/src/hotspot/share/runtime/abstract_vm_version.hpp +++ b/src/hotspot/share/runtime/abstract_vm_version.hpp @@ -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); diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index 77fae3becb5f3..c47ad7092a8be 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -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 + diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/amd64/AMD64.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/amd64/AMD64.java index d25f7e7199056..c75b3d9f9ce85 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/amd64/AMD64.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/amd64/AMD64.java @@ -258,6 +258,8 @@ public enum CPUFeature implements CPUFeatureName { APX_F, SHA512, AVX512_FP16, + AVX10_1, + AVX10_2 } private final EnumSet features; diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIBackendFactory.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIBackendFactory.java index 27fd3d23980de..319b9b9bc44d7 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIBackendFactory.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIBackendFactory.java @@ -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 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 @@ static > EnumSet con } return outFeatures; } + + /** + * Converts CPU features bit map into enum constants. + * + * @param 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 > EnumSet convertFeatures( + Class enumType, + Map constants, + long featuresBitMapAddress, + long featuresBitMapSize, + Map renaming) { + EnumSet outFeatures = EnumSet.noneOf(enumType); + List missing = new ArrayList<>(); + + for (Entry 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; + } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/amd64/AMD64HotSpotJVMCIBackendFactory.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/amd64/AMD64HotSpotJVMCIBackendFactory.java index 821bd9371b2d7..658bafea36dd3 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/amd64/AMD64HotSpotJVMCIBackendFactory.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/amd64/AMD64HotSpotJVMCIBackendFactory.java @@ -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 @@ private static EnumSet computeFeatures(AMD64HotSpotVMConfig config) Map constants = config.getStore().getConstants(); Map renaming = Map.of("3DNOW_PREFETCH", "AMD_3DNOW_PREFETCH"); assert config.useSSE >= 2 : "minimum config for x64"; - EnumSet features = HotSpotJVMCIBackendFactory.convertFeatures(CPUFeature.class, constants, config.vmVersionFeatures, renaming); + long featuresBitMapAddress = config.vmVersionFeatures + config.vmFeaturesFeaturesOffset; + EnumSet features = HotSpotJVMCIBackendFactory.convertFeatures(CPUFeature.class, + constants, + featuresBitMapAddress, + config.vmFeaturesFeaturesSize, + renaming); features.add(AMD64.CPUFeature.SSE); features.add(AMD64.CPUFeature.SSE2); return features; diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/amd64/AMD64HotSpotVMConfig.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/amd64/AMD64HotSpotVMConfig.java index b0e2f425dae4f..05803bdbfc784 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/amd64/AMD64HotSpotVMConfig.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/amd64/AMD64HotSpotVMConfig.java @@ -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); } diff --git a/test/hotspot/jtreg/serviceability/sa/ClhsdbLongConstant.java b/test/hotspot/jtreg/serviceability/sa/ClhsdbLongConstant.java index ba65cb40e6dbc..fceb2097e4625 100644 --- a/test/hotspot/jtreg/serviceability/sa/ClhsdbLongConstant.java +++ b/test/hotspot/jtreg/serviceability/sa/ClhsdbLongConstant.java @@ -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 @@ private static void checkForTruncation(String longConstantOutput) throws Excepti // 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 @@ private static void checkForTruncation(String longConstantOutput) throws Excepti // Expected value obtained from the CPU_SHA definition in vm_version_x86.hpp checkLongValue("VM_Version::CPU_SHA ", longConstantOutput, - 17179869184L); + 34L); } } diff --git a/test/lib-test/jdk/test/whitebox/CPUInfoTest.java b/test/lib-test/jdk/test/whitebox/CPUInfoTest.java index 54a9ef872f5f2..8f0ef1088857e 100644 --- a/test/lib-test/jdk/test/whitebox/CPUInfoTest.java +++ b/test/lib-test/jdk/test/whitebox/CPUInfoTest.java @@ -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