| /* |
| * Copyright (c) 1997, 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 |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| * |
| */ |
| |
| #include "asm/macroAssembler.hpp" |
| #include "asm/macroAssembler.inline.hpp" |
| #include "classfile/vmIntrinsics.hpp" |
| #include "code/codeBlob.hpp" |
| #include "compiler/compilerDefinitions.inline.hpp" |
| #include "jvm.h" |
| #include "logging/log.hpp" |
| #include "logging/logStream.hpp" |
| #include "memory/resourceArea.hpp" |
| #include "memory/universe.hpp" |
| #include "runtime/globals_extension.hpp" |
| #include "runtime/java.hpp" |
| #include "runtime/os.inline.hpp" |
| #include "runtime/stubCodeGenerator.hpp" |
| #include "runtime/vm_version.hpp" |
| #include "utilities/checkedCast.hpp" |
| #include "utilities/powerOfTwo.hpp" |
| #include "utilities/virtualizationSupport.hpp" |
| |
| int VM_Version::_cpu; |
| int VM_Version::_model; |
| int VM_Version::_stepping; |
| bool VM_Version::_has_intel_jcc_erratum; |
| VM_Version::CpuidInfo VM_Version::_cpuid_info = { 0, }; |
| |
| #define DECLARE_CPU_FEATURE_NAME(id, name, bit) name, |
| const char* VM_Version::_features_names[] = { CPU_FEATURE_FLAGS(DECLARE_CPU_FEATURE_NAME)}; |
| #undef DECLARE_CPU_FEATURE_FLAG |
| |
| // Address of instruction which causes SEGV |
| address VM_Version::_cpuinfo_segv_addr = nullptr; |
| // Address of instruction after the one which causes SEGV |
| address VM_Version::_cpuinfo_cont_addr = nullptr; |
| // Address of instruction which causes APX specific SEGV |
| address VM_Version::_cpuinfo_segv_addr_apx = nullptr; |
| // Address of instruction after the one which causes APX specific SEGV |
| 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*); |
| typedef void (*clear_apx_test_state_t)(void); |
| } |
| static get_cpu_info_stub_t get_cpu_info_stub = nullptr; |
| static detect_virt_stub_t detect_virt_stub = nullptr; |
| static clear_apx_test_state_t clear_apx_test_state_stub = nullptr; |
| |
| bool VM_Version::supports_clflush() { |
| // 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. |
| // Unfortunately, Assembler::clflush is currently called as part |
| // of generation of the code cache flush routine. This happens |
| // under Universe::init before the processor features are set |
| // 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.supports_feature(CPU_FLUSH)), "clflush should be available"); |
| return true; |
| } |
| |
| #define CPUID_STANDARD_FN 0x0 |
| #define CPUID_STANDARD_FN_1 0x1 |
| #define CPUID_STANDARD_FN_4 0x4 |
| #define CPUID_STANDARD_FN_B 0xb |
| |
| #define CPUID_EXTENDED_FN 0x80000000 |
| #define CPUID_EXTENDED_FN_1 0x80000001 |
| #define CPUID_EXTENDED_FN_2 0x80000002 |
| #define CPUID_EXTENDED_FN_3 0x80000003 |
| #define CPUID_EXTENDED_FN_4 0x80000004 |
| #define CPUID_EXTENDED_FN_7 0x80000007 |
| #define CPUID_EXTENDED_FN_8 0x80000008 |
| |
| class VM_Version_StubGenerator: public StubCodeGenerator { |
| public: |
| |
| VM_Version_StubGenerator(CodeBuffer *c) : StubCodeGenerator(c) {} |
| |
| address clear_apx_test_state() { |
| # define __ _masm-> |
| address start = __ pc(); |
| // EGPRs are call clobbered registers, Explicit clearing of r16 and r31 during signal |
| // handling guarantees that preserved register values post signal handling were |
| // re-instantiated by operating system and not because they were not modified externally. |
| |
| bool save_apx = UseAPX; |
| VM_Version::set_apx_cpuFeatures(); |
| UseAPX = true; |
| // EGPR state save/restoration. |
| __ mov64(r16, 0L); |
| __ mov64(r31, 0L); |
| UseAPX = save_apx; |
| VM_Version::clean_cpuFeatures(); |
| __ ret(0); |
| return start; |
| } |
| |
| address generate_get_cpu_info() { |
| // Flags to test CPU type. |
| const uint32_t HS_EFL_AC = 0x40000; |
| const uint32_t HS_EFL_ID = 0x200000; |
| // Values for when we don't have a CPUID instruction. |
| const int CPU_FAMILY_SHIFT = 8; |
| const uint32_t CPU_FAMILY_386 = (3 << CPU_FAMILY_SHIFT); |
| 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, std_cpuid24, std_cpuid29; |
| 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; |
| |
| StubCodeMark mark(this, "VM_Version", "get_cpu_info_stub"); |
| # define __ _masm-> |
| |
| address start = __ pc(); |
| |
| // |
| // void get_cpu_info(VM_Version::CpuidInfo* cpuid_info); |
| // |
| // rcx and rdx are first and second argument registers on windows |
| |
| __ push(rbp); |
| __ mov(rbp, c_rarg0); // cpuid_info address |
| __ push(rbx); |
| __ push(rsi); |
| __ pushf(); // preserve rbx, and flags |
| __ pop(rax); |
| __ push(rax); |
| __ mov(rcx, rax); |
| // |
| // if we are unable to change the AC flag, we have a 386 |
| // |
| __ xorl(rax, HS_EFL_AC); |
| __ push(rax); |
| __ popf(); |
| __ pushf(); |
| __ pop(rax); |
| __ cmpptr(rax, rcx); |
| __ jccb(Assembler::notEqual, detect_486); |
| |
| __ movl(rax, CPU_FAMILY_386); |
| __ movl(Address(rbp, in_bytes(VM_Version::std_cpuid1_offset())), rax); |
| __ jmp(done); |
| |
| // |
| // If we are unable to change the ID flag, we have a 486 which does |
| // not support the "cpuid" instruction. |
| // |
| __ bind(detect_486); |
| __ mov(rax, rcx); |
| __ xorl(rax, HS_EFL_ID); |
| __ push(rax); |
| __ popf(); |
| __ pushf(); |
| __ pop(rax); |
| __ cmpptr(rcx, rax); |
| __ jccb(Assembler::notEqual, detect_586); |
| |
| __ bind(cpu486); |
| __ movl(rax, CPU_FAMILY_486); |
| __ movl(Address(rbp, in_bytes(VM_Version::std_cpuid1_offset())), rax); |
| __ jmp(done); |
| |
| // |
| // At this point, we have a chip which supports the "cpuid" instruction |
| // |
| __ bind(detect_586); |
| __ xorl(rax, rax); |
| __ cpuid(); |
| __ orl(rax, rax); |
| __ jcc(Assembler::equal, cpu486); // if cpuid doesn't support an input |
| // value of at least 1, we give up and |
| // assume a 486 |
| __ lea(rsi, Address(rbp, in_bytes(VM_Version::std_cpuid0_offset()))); |
| __ movl(Address(rsi, 0), rax); |
| __ movl(Address(rsi, 4), rbx); |
| __ movl(Address(rsi, 8), rcx); |
| __ movl(Address(rsi,12), rdx); |
| |
| __ cmpl(rax, 0xa); // Is cpuid(0xB) supported? |
| __ jccb(Assembler::belowEqual, std_cpuid4); |
| |
| // |
| // cpuid(0xB) Processor Topology |
| // |
| __ movl(rax, 0xb); |
| __ xorl(rcx, rcx); // Threads level |
| __ cpuid(); |
| |
| __ lea(rsi, Address(rbp, in_bytes(VM_Version::tpl_cpuidB0_offset()))); |
| __ movl(Address(rsi, 0), rax); |
| __ movl(Address(rsi, 4), rbx); |
| __ movl(Address(rsi, 8), rcx); |
| __ movl(Address(rsi,12), rdx); |
| |
| __ movl(rax, 0xb); |
| __ movl(rcx, 1); // Cores level |
| __ cpuid(); |
| __ push(rax); |
| __ andl(rax, 0x1f); // Determine if valid topology level |
| __ orl(rax, rbx); // eax[4:0] | ebx[0:15] == 0 indicates invalid level |
| __ andl(rax, 0xffff); |
| __ pop(rax); |
| __ jccb(Assembler::equal, std_cpuid4); |
| |
| __ lea(rsi, Address(rbp, in_bytes(VM_Version::tpl_cpuidB1_offset()))); |
| __ movl(Address(rsi, 0), rax); |
| __ movl(Address(rsi, 4), rbx); |
| __ movl(Address(rsi, 8), rcx); |
| __ movl(Address(rsi,12), rdx); |
| |
| __ movl(rax, 0xb); |
| __ movl(rcx, 2); // Packages level |
| __ cpuid(); |
| __ push(rax); |
| __ andl(rax, 0x1f); // Determine if valid topology level |
| __ orl(rax, rbx); // eax[4:0] | ebx[0:15] == 0 indicates invalid level |
| __ andl(rax, 0xffff); |
| __ pop(rax); |
| __ jccb(Assembler::equal, std_cpuid4); |
| |
| __ lea(rsi, Address(rbp, in_bytes(VM_Version::tpl_cpuidB2_offset()))); |
| __ movl(Address(rsi, 0), rax); |
| __ movl(Address(rsi, 4), rbx); |
| __ movl(Address(rsi, 8), rcx); |
| __ movl(Address(rsi,12), rdx); |
| |
| // |
| // cpuid(0x4) Deterministic cache params |
| // |
| __ bind(std_cpuid4); |
| __ movl(rax, 4); |
| __ cmpl(rax, Address(rbp, in_bytes(VM_Version::std_cpuid0_offset()))); // Is cpuid(0x4) supported? |
| __ jccb(Assembler::greater, std_cpuid1); |
| |
| __ xorl(rcx, rcx); // L1 cache |
| __ cpuid(); |
| __ push(rax); |
| __ andl(rax, 0x1f); // Determine if valid cache parameters used |
| __ orl(rax, rax); // eax[4:0] == 0 indicates invalid cache |
| __ pop(rax); |
| __ jccb(Assembler::equal, std_cpuid1); |
| |
| __ lea(rsi, Address(rbp, in_bytes(VM_Version::dcp_cpuid4_offset()))); |
| __ movl(Address(rsi, 0), rax); |
| __ movl(Address(rsi, 4), rbx); |
| __ movl(Address(rsi, 8), rcx); |
| __ movl(Address(rsi,12), rdx); |
| |
| // |
| // Standard cpuid(0x1) |
| // |
| __ bind(std_cpuid1); |
| __ movl(rax, 1); |
| __ cpuid(); |
| __ lea(rsi, Address(rbp, in_bytes(VM_Version::std_cpuid1_offset()))); |
| __ movl(Address(rsi, 0), rax); |
| __ movl(Address(rsi, 4), rbx); |
| __ movl(Address(rsi, 8), rcx); |
| __ movl(Address(rsi,12), rdx); |
| |
| // |
| // Check if OS has enabled XGETBV instruction to access XCR0 |
| // (OSXSAVE feature flag) and CPU supports AVX |
| // |
| __ andl(rcx, 0x18000000); // cpuid1 bits osxsave | avx |
| __ cmpl(rcx, 0x18000000); |
| __ jccb(Assembler::notEqual, sef_cpuid); // jump if AVX is not supported |
| |
| // |
| // XCR0, XFEATURE_ENABLED_MASK register |
| // |
| __ xorl(rcx, rcx); // zero for XCR0 register |
| __ xgetbv(); |
| __ lea(rsi, Address(rbp, in_bytes(VM_Version::xem_xcr0_offset()))); |
| __ movl(Address(rsi, 0), rax); |
| __ movl(Address(rsi, 4), rdx); |
| |
| // |
| // cpuid(0x7) Structured Extended Features Enumeration Leaf. |
| // |
| __ bind(sef_cpuid); |
| __ movl(rax, 7); |
| __ cmpl(rax, Address(rbp, in_bytes(VM_Version::std_cpuid0_offset()))); // Is cpuid(0x7) supported? |
| __ jccb(Assembler::greater, ext_cpuid); |
| // ECX = 0 |
| __ xorl(rcx, rcx); |
| __ cpuid(); |
| __ lea(rsi, Address(rbp, in_bytes(VM_Version::sef_cpuid7_offset()))); |
| __ movl(Address(rsi, 0), rax); |
| __ movl(Address(rsi, 4), rbx); |
| __ movl(Address(rsi, 8), rcx); |
| __ movl(Address(rsi, 12), rdx); |
| |
| // |
| // cpuid(0x7) Structured Extended Features Enumeration Sub-Leaf 1. |
| // |
| __ bind(sefsl1_cpuid); |
| __ movl(rax, 7); |
| __ movl(rcx, 1); |
| __ cpuid(); |
| __ lea(rsi, Address(rbp, in_bytes(VM_Version::sefsl1_cpuid7_offset()))); |
| __ movl(Address(rsi, 0), rax); |
| __ movl(Address(rsi, 4), rdx); |
| |
| // |
| // cpuid(0x29) APX NCI NDD NF (EAX = 29H, ECX = 0). |
| // |
| __ bind(std_cpuid29); |
| __ movl(rax, 0x29); |
| __ movl(rcx, 0); |
| __ cpuid(); |
| __ lea(rsi, Address(rbp, in_bytes(VM_Version::std_cpuid29_offset()))); |
| __ movl(Address(rsi, 0), rbx); |
| |
| // |
| // 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) |
| // |
| __ bind(ext_cpuid); |
| __ movl(rax, 0x80000000); |
| __ cpuid(); |
| __ cmpl(rax, 0x80000000); // Is cpuid(0x80000001) supported? |
| __ jcc(Assembler::belowEqual, done); |
| __ cmpl(rax, 0x80000004); // Is cpuid(0x80000005) supported? |
| __ jcc(Assembler::belowEqual, ext_cpuid1); |
| __ cmpl(rax, 0x80000006); // Is cpuid(0x80000007) supported? |
| __ jccb(Assembler::belowEqual, ext_cpuid5); |
| __ cmpl(rax, 0x80000007); // Is cpuid(0x80000008) supported? |
| __ jccb(Assembler::belowEqual, ext_cpuid7); |
| __ cmpl(rax, 0x80000008); // Is cpuid(0x80000009 and above) supported? |
| __ jccb(Assembler::belowEqual, ext_cpuid8); |
| __ cmpl(rax, 0x8000001E); // Is cpuid(0x8000001E) supported? |
| __ jccb(Assembler::below, ext_cpuid8); |
| // |
| // Extended cpuid(0x8000001E) |
| // |
| __ movl(rax, 0x8000001E); |
| __ cpuid(); |
| __ lea(rsi, Address(rbp, in_bytes(VM_Version::ext_cpuid1E_offset()))); |
| __ movl(Address(rsi, 0), rax); |
| __ movl(Address(rsi, 4), rbx); |
| __ movl(Address(rsi, 8), rcx); |
| __ movl(Address(rsi,12), rdx); |
| |
| // |
| // Extended cpuid(0x80000008) |
| // |
| __ bind(ext_cpuid8); |
| __ movl(rax, 0x80000008); |
| __ cpuid(); |
| __ lea(rsi, Address(rbp, in_bytes(VM_Version::ext_cpuid8_offset()))); |
| __ movl(Address(rsi, 0), rax); |
| __ movl(Address(rsi, 4), rbx); |
| __ movl(Address(rsi, 8), rcx); |
| __ movl(Address(rsi,12), rdx); |
| |
| // |
| // Extended cpuid(0x80000007) |
| // |
| __ bind(ext_cpuid7); |
| __ movl(rax, 0x80000007); |
| __ cpuid(); |
| __ lea(rsi, Address(rbp, in_bytes(VM_Version::ext_cpuid7_offset()))); |
| __ movl(Address(rsi, 0), rax); |
| __ movl(Address(rsi, 4), rbx); |
| __ movl(Address(rsi, 8), rcx); |
| __ movl(Address(rsi,12), rdx); |
| |
| // |
| // Extended cpuid(0x80000005) |
| // |
| __ bind(ext_cpuid5); |
| __ movl(rax, 0x80000005); |
| __ cpuid(); |
| __ lea(rsi, Address(rbp, in_bytes(VM_Version::ext_cpuid5_offset()))); |
| __ movl(Address(rsi, 0), rax); |
| __ movl(Address(rsi, 4), rbx); |
| __ movl(Address(rsi, 8), rcx); |
| __ movl(Address(rsi,12), rdx); |
| |
| // |
| // Extended cpuid(0x80000001) |
| // |
| __ bind(ext_cpuid1); |
| __ movl(rax, 0x80000001); |
| __ cpuid(); |
| __ lea(rsi, Address(rbp, in_bytes(VM_Version::ext_cpuid1_offset()))); |
| __ movl(Address(rsi, 0), rax); |
| __ movl(Address(rsi, 4), rbx); |
| __ movl(Address(rsi, 8), rcx); |
| __ movl(Address(rsi,12), rdx); |
| |
| // |
| // Check if OS has enabled XGETBV instruction to access XCR0 |
| // (OSXSAVE feature flag) and CPU supports APX |
| // |
| // To enable APX, check CPUID.EAX=7.ECX=1.EDX[21] bit for HW support |
| // and XCRO[19] bit for OS support to save/restore extended GPR state. |
| __ lea(rsi, Address(rbp, in_bytes(VM_Version::sefsl1_cpuid7_offset()))); |
| __ movl(rax, 0x200000); |
| __ andl(rax, Address(rsi, 4)); |
| __ 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 |
| __ jcc(Assembler::equal, vector_save_restore); |
| |
| bool save_apx = UseAPX; |
| VM_Version::set_apx_cpuFeatures(); |
| UseAPX = true; |
| __ mov64(r16, VM_Version::egpr_test_value()); |
| __ mov64(r31, VM_Version::egpr_test_value()); |
| __ xorl(rsi, rsi); |
| VM_Version::set_cpuinfo_segv_addr_apx(__ pc()); |
| // Generate SEGV |
| __ movl(rax, Address(rsi, 0)); |
| |
| VM_Version::set_cpuinfo_cont_addr_apx(__ pc()); |
| __ lea(rsi, Address(rbp, in_bytes(VM_Version::apx_save_offset()))); |
| __ movq(Address(rsi, 0), r16); |
| __ movq(Address(rsi, 8), r31); |
| |
| UseAPX = save_apx; |
| __ bind(vector_save_restore); |
| // |
| // Check if OS has enabled XGETBV instruction to access XCR0 |
| // (OSXSAVE feature flag) and CPU supports AVX |
| // |
| __ lea(rsi, Address(rbp, in_bytes(VM_Version::std_cpuid1_offset()))); |
| __ movl(rcx, 0x18000000); // cpuid1 bits osxsave | avx |
| __ andl(rcx, Address(rsi, 8)); // cpuid1 bits osxsave | avx |
| __ cmpl(rcx, 0x18000000); |
| __ jccb(Assembler::notEqual, done); // jump if AVX is not supported |
| |
| __ movl(rax, 0x6); |
| __ andl(rax, Address(rbp, in_bytes(VM_Version::xem_xcr0_offset()))); // xcr0 bits sse | ymm |
| __ cmpl(rax, 0x6); |
| __ jccb(Assembler::equal, start_simd_check); // return if AVX is not supported |
| |
| // we need to bridge farther than imm8, so we use this island as a thunk |
| __ bind(done); |
| __ jmp(wrapup); |
| |
| __ bind(start_simd_check); |
| // |
| // Some OSs have a bug when upper 128/256bits of YMM/ZMM |
| // registers are not restored after a signal processing. |
| // Generate SEGV here (reference through null) |
| // and check upper YMM/ZMM bits after it. |
| // |
| int saved_useavx = UseAVX; |
| int saved_usesse = UseSSE; |
| |
| // 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)); |
| __ 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 |
| __ movl(rax, 0xE0); |
| __ andl(rax, Address(rbp, in_bytes(VM_Version::xem_xcr0_offset()))); // xcr0 bits sse | ymm |
| __ cmpl(rax, 0xE0); |
| __ jccb(Assembler::notEqual, legacy_setup); // jump if EVEX is not supported |
| |
| if (FLAG_IS_DEFAULT(UseAVX)) { |
| __ lea(rsi, Address(rbp, in_bytes(VM_Version::std_cpuid1_offset()))); |
| __ movl(rax, Address(rsi, 0)); |
| __ cmpl(rax, 0x50654); // If it is Skylake |
| __ jcc(Assembler::equal, legacy_setup); |
| } |
| // EVEX setup: run in lowest evex mode |
| VM_Version::set_evex_cpuFeatures(); // Enable temporary to pass asserts |
| UseAVX = 3; |
| UseSSE = 2; |
| #ifdef _WINDOWS |
| // xmm5-xmm15 are not preserved by caller on windows |
| // https://msdn.microsoft.com/en-us/library/9z1stfyw.aspx |
| __ subptr(rsp, 64); |
| __ evmovdqul(Address(rsp, 0), xmm7, Assembler::AVX_512bit); |
| __ subptr(rsp, 64); |
| __ evmovdqul(Address(rsp, 0), xmm8, Assembler::AVX_512bit); |
| __ subptr(rsp, 64); |
| __ evmovdqul(Address(rsp, 0), xmm31, Assembler::AVX_512bit); |
| #endif // _WINDOWS |
| |
| // load value into all 64 bytes of zmm7 register |
| __ movl(rcx, VM_Version::ymm_test_value()); |
| __ movdl(xmm0, rcx); |
| __ vpbroadcastd(xmm0, xmm0, Assembler::AVX_512bit); |
| __ evmovdqul(xmm7, xmm0, Assembler::AVX_512bit); |
| __ evmovdqul(xmm8, xmm0, Assembler::AVX_512bit); |
| __ evmovdqul(xmm31, xmm0, Assembler::AVX_512bit); |
| VM_Version::clean_cpuFeatures(); |
| __ jmp(save_restore_except); |
| } |
| |
| __ bind(legacy_setup); |
| // AVX setup |
| VM_Version::set_avx_cpuFeatures(); // Enable temporary to pass asserts |
| UseAVX = 1; |
| UseSSE = 2; |
| #ifdef _WINDOWS |
| __ subptr(rsp, 32); |
| __ vmovdqu(Address(rsp, 0), xmm7); |
| __ subptr(rsp, 32); |
| __ vmovdqu(Address(rsp, 0), xmm8); |
| __ subptr(rsp, 32); |
| __ vmovdqu(Address(rsp, 0), xmm15); |
| #endif // _WINDOWS |
| |
| // load value into all 32 bytes of ymm7 register |
| __ movl(rcx, VM_Version::ymm_test_value()); |
| |
| __ movdl(xmm0, rcx); |
| __ pshufd(xmm0, xmm0, 0x00); |
| __ vinsertf128_high(xmm0, xmm0); |
| __ vmovdqu(xmm7, xmm0); |
| __ vmovdqu(xmm8, xmm0); |
| __ vmovdqu(xmm15, xmm0); |
| VM_Version::clean_cpuFeatures(); |
| |
| __ bind(save_restore_except); |
| __ xorl(rsi, rsi); |
| VM_Version::set_cpuinfo_segv_addr(__ pc()); |
| // Generate SEGV |
| __ movl(rax, Address(rsi, 0)); |
| |
| VM_Version::set_cpuinfo_cont_addr(__ pc()); |
| // Returns here after signal. Save xmm0 to check it later. |
| |
| // If UseAVX is uninitialized or is set by the user to include EVEX |
| if (use_evex) { |
| // check _cpuid_info.sef_cpuid7_ebx.bits.avx512f |
| __ lea(rsi, Address(rbp, in_bytes(VM_Version::sef_cpuid7_offset()))); |
| __ movl(rax, 0x10000); |
| __ andl(rax, Address(rsi, 4)); |
| __ 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 |
| __ movl(rax, 0xE0); |
| __ andl(rax, Address(rbp, in_bytes(VM_Version::xem_xcr0_offset()))); // xcr0 bits sse | ymm |
| __ cmpl(rax, 0xE0); |
| __ jcc(Assembler::notEqual, legacy_save_restore); |
| |
| if (FLAG_IS_DEFAULT(UseAVX)) { |
| __ lea(rsi, Address(rbp, in_bytes(VM_Version::std_cpuid1_offset()))); |
| __ movl(rax, Address(rsi, 0)); |
| __ cmpl(rax, 0x50654); // If it is Skylake |
| __ jcc(Assembler::equal, legacy_save_restore); |
| } |
| // EVEX check: run in lowest evex mode |
| VM_Version::set_evex_cpuFeatures(); // Enable temporary to pass asserts |
| UseAVX = 3; |
| UseSSE = 2; |
| __ lea(rsi, Address(rbp, in_bytes(VM_Version::zmm_save_offset()))); |
| __ evmovdqul(Address(rsi, 0), xmm0, Assembler::AVX_512bit); |
| __ evmovdqul(Address(rsi, 64), xmm7, Assembler::AVX_512bit); |
| __ evmovdqul(Address(rsi, 128), xmm8, Assembler::AVX_512bit); |
| __ evmovdqul(Address(rsi, 192), xmm31, Assembler::AVX_512bit); |
| |
| #ifdef _WINDOWS |
| __ evmovdqul(xmm31, Address(rsp, 0), Assembler::AVX_512bit); |
| __ addptr(rsp, 64); |
| __ evmovdqul(xmm8, Address(rsp, 0), Assembler::AVX_512bit); |
| __ addptr(rsp, 64); |
| __ evmovdqul(xmm7, Address(rsp, 0), Assembler::AVX_512bit); |
| __ addptr(rsp, 64); |
| #endif // _WINDOWS |
| generate_vzeroupper(wrapup); |
| VM_Version::clean_cpuFeatures(); |
| UseAVX = saved_useavx; |
| UseSSE = saved_usesse; |
| __ jmp(wrapup); |
| } |
| |
| __ bind(legacy_save_restore); |
| // AVX check |
| VM_Version::set_avx_cpuFeatures(); // Enable temporary to pass asserts |
| UseAVX = 1; |
| UseSSE = 2; |
| __ lea(rsi, Address(rbp, in_bytes(VM_Version::ymm_save_offset()))); |
| __ vmovdqu(Address(rsi, 0), xmm0); |
| __ vmovdqu(Address(rsi, 32), xmm7); |
| __ vmovdqu(Address(rsi, 64), xmm8); |
| __ vmovdqu(Address(rsi, 96), xmm15); |
| |
| #ifdef _WINDOWS |
| __ vmovdqu(xmm15, Address(rsp, 0)); |
| __ addptr(rsp, 32); |
| __ vmovdqu(xmm8, Address(rsp, 0)); |
| __ addptr(rsp, 32); |
| __ vmovdqu(xmm7, Address(rsp, 0)); |
| __ addptr(rsp, 32); |
| #endif // _WINDOWS |
| |
| generate_vzeroupper(wrapup); |
| VM_Version::clean_cpuFeatures(); |
| UseAVX = saved_useavx; |
| UseSSE = saved_usesse; |
| |
| __ bind(wrapup); |
| __ popf(); |
| __ pop(rsi); |
| __ pop(rbx); |
| __ pop(rbp); |
| __ ret(0); |
| |
| # undef __ |
| |
| return start; |
| }; |
| void generate_vzeroupper(Label& L_wrapup) { |
| # define __ _masm-> |
| __ lea(rsi, Address(rbp, in_bytes(VM_Version::std_cpuid0_offset()))); |
| __ cmpl(Address(rsi, 4), 0x756e6547); // 'uneG' |
| __ jcc(Assembler::notEqual, L_wrapup); |
| __ movl(rcx, 0x0FFF0FF0); |
| __ lea(rsi, Address(rbp, in_bytes(VM_Version::std_cpuid1_offset()))); |
| __ andl(rcx, Address(rsi, 0)); |
| __ cmpl(rcx, 0x00050670); // If it is Xeon Phi 3200/5200/7200 |
| __ jcc(Assembler::equal, L_wrapup); |
| __ cmpl(rcx, 0x00080650); // If it is Future Xeon Phi |
| __ jcc(Assembler::equal, L_wrapup); |
| // vzeroupper() will use a pre-computed instruction sequence that we |
| // can't compute until after we've determined CPU capabilities. Use |
| // uncached variant here directly to be able to bootstrap correctly |
| __ vzeroupper_uncached(); |
| # undef __ |
| } |
| address generate_detect_virt() { |
| StubCodeMark mark(this, "VM_Version", "detect_virt_stub"); |
| # define __ _masm-> |
| |
| address start = __ pc(); |
| |
| // Evacuate callee-saved registers |
| __ push(rbp); |
| __ push(rbx); |
| __ push(rsi); // for Windows |
| |
| __ mov(rax, c_rarg0); // CPUID leaf |
| __ mov(rsi, c_rarg1); // register array address (eax, ebx, ecx, edx) |
| |
| __ cpuid(); |
| |
| // Store result to register array |
| __ movl(Address(rsi, 0), rax); |
| __ movl(Address(rsi, 4), rbx); |
| __ movl(Address(rsi, 8), rcx); |
| __ movl(Address(rsi, 12), rdx); |
| |
| // Epilogue |
| __ pop(rsi); |
| __ pop(rbx); |
| __ pop(rbp); |
| __ ret(0); |
| |
| # undef __ |
| |
| return start; |
| }; |
| |
| |
| address generate_getCPUIDBrandString(void) { |
| // Flags to test CPU type. |
| const uint32_t HS_EFL_AC = 0x40000; |
| const uint32_t HS_EFL_ID = 0x200000; |
| // Values for when we don't have a CPUID instruction. |
| const int CPU_FAMILY_SHIFT = 8; |
| const uint32_t CPU_FAMILY_386 = (3 << CPU_FAMILY_SHIFT); |
| const uint32_t CPU_FAMILY_486 = (4 << CPU_FAMILY_SHIFT); |
| |
| Label detect_486, cpu486, detect_586, done, ext_cpuid; |
| |
| StubCodeMark mark(this, "VM_Version", "getCPUIDNameInfo_stub"); |
| # define __ _masm-> |
| |
| address start = __ pc(); |
| |
| // |
| // void getCPUIDBrandString(VM_Version::CpuidInfo* cpuid_info); |
| // |
| // rcx and rdx are first and second argument registers on windows |
| |
| __ push(rbp); |
| __ mov(rbp, c_rarg0); // cpuid_info address |
| __ push(rbx); |
| __ push(rsi); |
| __ pushf(); // preserve rbx, and flags |
| __ pop(rax); |
| __ push(rax); |
| __ mov(rcx, rax); |
| // |
| // if we are unable to change the AC flag, we have a 386 |
| // |
| __ xorl(rax, HS_EFL_AC); |
| __ push(rax); |
| __ popf(); |
| __ pushf(); |
| __ pop(rax); |
| __ cmpptr(rax, rcx); |
| __ jccb(Assembler::notEqual, detect_486); |
| |
| __ movl(rax, CPU_FAMILY_386); |
| __ jmp(done); |
| |
| // |
| // If we are unable to change the ID flag, we have a 486 which does |
| // not support the "cpuid" instruction. |
| // |
| __ bind(detect_486); |
| __ mov(rax, rcx); |
| __ xorl(rax, HS_EFL_ID); |
| __ push(rax); |
| __ popf(); |
| __ pushf(); |
| __ pop(rax); |
| __ cmpptr(rcx, rax); |
| __ jccb(Assembler::notEqual, detect_586); |
| |
| __ bind(cpu486); |
| __ movl(rax, CPU_FAMILY_486); |
| __ jmp(done); |
| |
| // |
| // At this point, we have a chip which supports the "cpuid" instruction |
| // |
| __ bind(detect_586); |
| __ xorl(rax, rax); |
| __ cpuid(); |
| __ orl(rax, rax); |
| __ jcc(Assembler::equal, cpu486); // if cpuid doesn't support an input |
| // value of at least 1, we give up and |
| // assume a 486 |
| |
| // |
| // Extended cpuid(0x80000000) for processor brand string detection |
| // |
| __ bind(ext_cpuid); |
| __ movl(rax, CPUID_EXTENDED_FN); |
| __ cpuid(); |
| __ cmpl(rax, CPUID_EXTENDED_FN_4); |
| __ jcc(Assembler::below, done); |
| |
| // |
| // Extended cpuid(0x80000002) // first 16 bytes in brand string |
| // |
| __ movl(rax, CPUID_EXTENDED_FN_2); |
| __ cpuid(); |
| __ lea(rsi, Address(rbp, in_bytes(VM_Version::proc_name_0_offset()))); |
| __ movl(Address(rsi, 0), rax); |
| __ lea(rsi, Address(rbp, in_bytes(VM_Version::proc_name_1_offset()))); |
| __ movl(Address(rsi, 0), rbx); |
| __ lea(rsi, Address(rbp, in_bytes(VM_Version::proc_name_2_offset()))); |
| __ movl(Address(rsi, 0), rcx); |
| __ lea(rsi, Address(rbp, in_bytes(VM_Version::proc_name_3_offset()))); |
| __ movl(Address(rsi,0), rdx); |
| |
| // |
| // Extended cpuid(0x80000003) // next 16 bytes in brand string |
| // |
| __ movl(rax, CPUID_EXTENDED_FN_3); |
| __ cpuid(); |
| __ lea(rsi, Address(rbp, in_bytes(VM_Version::proc_name_4_offset()))); |
| __ movl(Address(rsi, 0), rax); |
| __ lea(rsi, Address(rbp, in_bytes(VM_Version::proc_name_5_offset()))); |
| __ movl(Address(rsi, 0), rbx); |
| __ lea(rsi, Address(rbp, in_bytes(VM_Version::proc_name_6_offset()))); |
| __ movl(Address(rsi, 0), rcx); |
| __ lea(rsi, Address(rbp, in_bytes(VM_Version::proc_name_7_offset()))); |
| __ movl(Address(rsi,0), rdx); |
| |
| // |
| // Extended cpuid(0x80000004) // last 16 bytes in brand string |
| // |
| __ movl(rax, CPUID_EXTENDED_FN_4); |
| __ cpuid(); |
| __ lea(rsi, Address(rbp, in_bytes(VM_Version::proc_name_8_offset()))); |
| __ movl(Address(rsi, 0), rax); |
| __ lea(rsi, Address(rbp, in_bytes(VM_Version::proc_name_9_offset()))); |
| __ movl(Address(rsi, 0), rbx); |
| __ lea(rsi, Address(rbp, in_bytes(VM_Version::proc_name_10_offset()))); |
| __ movl(Address(rsi, 0), rcx); |
| __ lea(rsi, Address(rbp, in_bytes(VM_Version::proc_name_11_offset()))); |
| __ movl(Address(rsi,0), rdx); |
| |
| // |
| // return |
| // |
| __ bind(done); |
| __ popf(); |
| __ pop(rsi); |
| __ pop(rbx); |
| __ pop(rbp); |
| __ ret(0); |
| |
| # undef __ |
| |
| return start; |
| }; |
| }; |
| |
| void VM_Version::get_processor_features() { |
| |
| _cpu = 4; // 486 by default |
| _model = 0; |
| _stepping = 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; |
| |
| // Get raw processor info |
| |
| get_cpu_info_stub(&_cpuid_info); |
| |
| assert_is_initialized(); |
| _cpu = extended_cpu_family(); |
| _model = extended_cpu_model(); |
| _stepping = cpu_stepping(); |
| |
| if (cpu_family() > 4) { // it supports CPUID |
| _features = _cpuid_info.feature_flags(); // These can be changed by VM settings |
| _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(); |
| _L1_data_cache_line_size = L1_line_size(); |
| } |
| |
| // xchg and xadd instructions |
| _supports_atomic_getset4 = true; |
| _supports_atomic_getadd4 = true; |
| _supports_atomic_getset8 = true; |
| _supports_atomic_getadd8 = true; |
| |
| // OS should support SSE for x64 and hardware should support at least SSE2. |
| if (!VM_Version::supports_sse2()) { |
| vm_exit_during_initialization("Unknown x64 processor: SSE2 not supported"); |
| } |
| // in 64 bit the use of SSE2 is the minimum |
| if (UseSSE < 2) UseSSE = 2; |
| |
| // flush_icache_stub have to be generated first. |
| // That is why Icache line size is hard coded in ICache class, |
| // see icache_x86.hpp. It is also the reason why we can't use |
| // clflush instruction in 32-bit VM since it could be running |
| // on CPU which does not support it. |
| // |
| // The only thing we can do is to verify that flushed |
| // ICache::line_size has correct value. |
| guarantee(_cpuid_info.std_cpuid1_edx.bits.clflush != 0, "clflush is not supported"); |
| // clflush_size is size in quadwords (8 bytes). |
| guarantee(_cpuid_info.std_cpuid1_ebx.bits.clflush_size == 8, "such clflush size is not supported"); |
| |
| // assigning this field effectively enables Unsafe.writebackMemory() |
| // by initing UnsafeConstant.DATA_CACHE_LINE_FLUSH_SIZE to non-zero |
| // that is only implemented on x86_64 and only if the OS plays ball |
| if (os::supports_map_sync()) { |
| // publish data cache line flush size to generic field, otherwise |
| // let if default to zero thereby disabling writeback |
| _data_cache_line_flush_size = _cpuid_info.std_cpuid1_ebx.bits.clflush_size * 8; |
| } |
| |
| // Check if processor has Intel Ecore |
| if (FLAG_IS_DEFAULT(EnableX86ECoreOpts) && is_intel() && is_intel_server_family() && |
| (_model == 0x97 || _model == 0xAA || _model == 0xAC || _model == 0xAF || |
| _model == 0xCC || _model == 0xDD)) { |
| FLAG_SET_DEFAULT(EnableX86ECoreOpts, true); |
| } |
| |
| if (UseSSE < 4) { |
| _features.clear_feature(CPU_SSE4_1); |
| _features.clear_feature(CPU_SSE4_2); |
| } |
| |
| if (UseSSE < 3) { |
| _features.clear_feature(CPU_SSE3); |
| _features.clear_feature(CPU_SSSE3); |
| _features.clear_feature(CPU_SSE4A); |
| } |
| |
| if (UseSSE < 2) |
| _features.clear_feature(CPU_SSE2); |
| |
| if (UseSSE < 1) |
| _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))) { |
| UseAVX = 0; |
| } |
| |
| // UseSSE is set to the smaller of what hardware supports and what |
| // the command line requires. I.e., you cannot set UseSSE to 2 on |
| // older Pentiums which do not support it. |
| int use_sse_limit = 0; |
| if (UseSSE > 0) { |
| if (UseSSE > 3 && supports_sse4_1()) { |
| use_sse_limit = 4; |
| } else if (UseSSE > 2 && supports_sse3()) { |
| use_sse_limit = 3; |
| } else if (UseSSE > 1 && supports_sse2()) { |
| use_sse_limit = 2; |
| } else if (UseSSE > 0 && supports_sse()) { |
| use_sse_limit = 1; |
| } else { |
| use_sse_limit = 0; |
| } |
| } |
| if (FLAG_IS_DEFAULT(UseSSE)) { |
| FLAG_SET_DEFAULT(UseSSE, use_sse_limit); |
| } else if (UseSSE > use_sse_limit) { |
| warning("UseSSE=%d is not supported on this CPU, setting it to UseSSE=%d", UseSSE, use_sse_limit); |
| FLAG_SET_DEFAULT(UseSSE, use_sse_limit); |
| } |
| |
| // first try initial setting and detect what we can support |
| int use_avx_limit = 0; |
| if (UseAVX > 0) { |
| if (UseSSE < 4) { |
| // Don't use AVX if SSE is unavailable or has been disabled. |
| use_avx_limit = 0; |
| } else if (UseAVX > 2 && supports_evex()) { |
| use_avx_limit = 3; |
| } else if (UseAVX > 1 && supports_avx2()) { |
| use_avx_limit = 2; |
| } else if (UseAVX > 0 && supports_avx()) { |
| use_avx_limit = 1; |
| } else { |
| use_avx_limit = 0; |
| } |
| } |
| if (FLAG_IS_DEFAULT(UseAVX)) { |
| // Don't use AVX-512 on older Skylakes unless explicitly requested. |
| if (use_avx_limit > 2 && is_intel_skylake() && _stepping < 5) { |
| FLAG_SET_DEFAULT(UseAVX, 2); |
| } else { |
| FLAG_SET_DEFAULT(UseAVX, use_avx_limit); |
| } |
| } |
| |
| if (UseAVX > use_avx_limit) { |
| if (UseSSE < 4) { |
| warning("UseAVX=%d requires UseSSE=4, setting it to UseAVX=0", UseAVX); |
| } else { |
| warning("UseAVX=%d is not supported on this CPU, setting it to UseAVX=%d", UseAVX, use_avx_limit); |
| } |
| FLAG_SET_DEFAULT(UseAVX, use_avx_limit); |
| } |
| |
| if (UseAVX < 3) { |
| _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); |
| } |
| |
| |
| if (UseAVX < 2) { |
| _features.clear_feature(CPU_AVX2); |
| _features.clear_feature(CPU_AVX_IFMA); |
| } |
| |
| if (UseAVX < 1) { |
| _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.clear_feature(CPU_HT); |
| } |
| |
| if (is_intel()) { // Intel cpus specific settings |
| if (is_knights_family()) { |
| _features.clear_feature(CPU_VZEROUPPER); |
| _features.clear_feature(CPU_AVX512BW); |
| _features.clear_feature(CPU_AVX512VL); |
| _features.clear_feature(CPU_APX_F); |
| _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); |
| } |
| } |
| |
| // Currently APX support is only enabled for targets supporting AVX512VL feature. |
| bool apx_supported = os_supports_apx_egprs() && supports_apx_f() && supports_avx512vl(); |
| if (UseAPX && !apx_supported) { |
| warning("UseAPX is not supported on this CPU, setting it to false"); |
| FLAG_SET_DEFAULT(UseAPX, false); |
| } |
| |
| if (!UseAPX) { |
| _features.clear_feature(CPU_APX_F); |
| } |
| |
| if (FLAG_IS_DEFAULT(IntelJccErratumMitigation)) { |
| _has_intel_jcc_erratum = compute_has_intel_jcc_erratum(); |
| FLAG_SET_ERGO(IntelJccErratumMitigation, _has_intel_jcc_erratum); |
| } else { |
| _has_intel_jcc_erratum = IntelJccErratumMitigation; |
| } |
| |
| assert(supports_clflush(), "Always present"); |
| if (X86ICacheSync == -1) { |
| // Auto-detect, choosing the best performant one that still flushes |
| // the cache. We could switch to CPUID/SERIALIZE ("4"/"5") going forward. |
| if (supports_clwb()) { |
| FLAG_SET_ERGO(X86ICacheSync, 3); |
| } else if (supports_clflushopt()) { |
| FLAG_SET_ERGO(X86ICacheSync, 2); |
| } else { |
| FLAG_SET_ERGO(X86ICacheSync, 1); |
| } |
| } else { |
| if ((X86ICacheSync == 2) && !supports_clflushopt()) { |
| vm_exit_during_initialization("CPU does not support CLFLUSHOPT, unable to use X86ICacheSync=2"); |
| } |
| if ((X86ICacheSync == 3) && !supports_clwb()) { |
| vm_exit_during_initialization("CPU does not support CLWB, unable to use X86ICacheSync=3"); |
| } |
| if ((X86ICacheSync == 5) && !supports_serialize()) { |
| vm_exit_during_initialization("CPU does not support SERIALIZE, unable to use X86ICacheSync=5"); |
| } |
| } |
| |
| 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(_features, buf + cpu_info_size, sizeof(buf) - cpu_info_size); |
| |
| _cpu_info_string = os::strdup(buf); |
| |
| _features_string = extract_features_string(_cpu_info_string, |
| strnlen(_cpu_info_string, sizeof(buf)), |
| cpu_info_size); |
| |
| // Use AES instructions if available. |
| if (supports_aes()) { |
| if (FLAG_IS_DEFAULT(UseAES)) { |
| FLAG_SET_DEFAULT(UseAES, true); |
| } |
| if (!UseAES) { |
| if (UseAESIntrinsics && !FLAG_IS_DEFAULT(UseAESIntrinsics)) { |
| warning("AES intrinsics require UseAES flag to be enabled. Intrinsics will be disabled."); |
| } |
| FLAG_SET_DEFAULT(UseAESIntrinsics, false); |
| } else { |
| if (UseSSE > 2) { |
| if (FLAG_IS_DEFAULT(UseAESIntrinsics)) { |
| FLAG_SET_DEFAULT(UseAESIntrinsics, true); |
| } |
| } else { |
| // The AES intrinsic stubs require AES instruction support (of course) |
| // but also require sse3 mode or higher for instructions it use. |
| if (UseAESIntrinsics && !FLAG_IS_DEFAULT(UseAESIntrinsics)) { |
| warning("X86 AES intrinsics require SSE3 instructions or higher. Intrinsics will be disabled."); |
| } |
| FLAG_SET_DEFAULT(UseAESIntrinsics, false); |
| } |
| |
| // --AES-CTR begins-- |
| if (!UseAESIntrinsics) { |
| if (UseAESCTRIntrinsics && !FLAG_IS_DEFAULT(UseAESCTRIntrinsics)) { |
| warning("AES-CTR intrinsics require UseAESIntrinsics flag to be enabled. Intrinsics will be disabled."); |
| FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false); |
| } |
| } else { |
| if (supports_sse4_1()) { |
| if (FLAG_IS_DEFAULT(UseAESCTRIntrinsics)) { |
| FLAG_SET_DEFAULT(UseAESCTRIntrinsics, true); |
| } |
| } else { |
| // The AES-CTR intrinsic stubs require AES instruction support (of course) |
| // but also require sse4.1 mode or higher for instructions it use. |
| if (UseAESCTRIntrinsics && !FLAG_IS_DEFAULT(UseAESCTRIntrinsics)) { |
| warning("X86 AES-CTR intrinsics require SSE4.1 instructions or higher. Intrinsics will be disabled."); |
| } |
| FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false); |
| } |
| } |
| // --AES-CTR ends-- |
| } |
| } else if (UseAES || UseAESIntrinsics || UseAESCTRIntrinsics) { |
| if (UseAES && !FLAG_IS_DEFAULT(UseAES)) { |
| warning("AES instructions are not available on this CPU"); |
| FLAG_SET_DEFAULT(UseAES, false); |
| } |
| if (UseAESIntrinsics && !FLAG_IS_DEFAULT(UseAESIntrinsics)) { |
| warning("AES intrinsics are not available on this CPU"); |
| FLAG_SET_DEFAULT(UseAESIntrinsics, false); |
| } |
| if (UseAESCTRIntrinsics && !FLAG_IS_DEFAULT(UseAESCTRIntrinsics)) { |
| warning("AES-CTR intrinsics are not available on this CPU"); |
| FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false); |
| } |
| } |
| |
| // Use CLMUL instructions if available. |
| if (supports_clmul()) { |
| if (FLAG_IS_DEFAULT(UseCLMUL)) { |
| UseCLMUL = true; |
| } |
| } else if (UseCLMUL) { |
| if (!FLAG_IS_DEFAULT(UseCLMUL)) |
| warning("CLMUL instructions not available on this CPU (AVX may also be required)"); |
| FLAG_SET_DEFAULT(UseCLMUL, false); |
| } |
| |
| if (UseCLMUL && (UseSSE > 2)) { |
| if (FLAG_IS_DEFAULT(UseCRC32Intrinsics)) { |
| UseCRC32Intrinsics = true; |
| } |
| } else if (UseCRC32Intrinsics) { |
| if (!FLAG_IS_DEFAULT(UseCRC32Intrinsics)) |
| warning("CRC32 Intrinsics requires CLMUL instructions (not available on this CPU)"); |
| FLAG_SET_DEFAULT(UseCRC32Intrinsics, false); |
| } |
| |
| if (supports_avx2()) { |
| if (FLAG_IS_DEFAULT(UseAdler32Intrinsics)) { |
| UseAdler32Intrinsics = true; |
| } |
| } else if (UseAdler32Intrinsics) { |
| if (!FLAG_IS_DEFAULT(UseAdler32Intrinsics)) { |
| warning("Adler32 Intrinsics requires avx2 instructions (not available on this CPU)"); |
| } |
| FLAG_SET_DEFAULT(UseAdler32Intrinsics, false); |
| } |
| |
| if (supports_sse4_2() && supports_clmul()) { |
| if (FLAG_IS_DEFAULT(UseCRC32CIntrinsics)) { |
| UseCRC32CIntrinsics = true; |
| } |
| } else if (UseCRC32CIntrinsics) { |
| if (!FLAG_IS_DEFAULT(UseCRC32CIntrinsics)) { |
| warning("CRC32C intrinsics are not available on this CPU"); |
| } |
| FLAG_SET_DEFAULT(UseCRC32CIntrinsics, false); |
| } |
| |
| // GHASH/GCM intrinsics |
| if (UseCLMUL && (UseSSE > 2)) { |
| if (FLAG_IS_DEFAULT(UseGHASHIntrinsics)) { |
| UseGHASHIntrinsics = true; |
| } |
| } else if (UseGHASHIntrinsics) { |
| if (!FLAG_IS_DEFAULT(UseGHASHIntrinsics)) |
| warning("GHASH intrinsic requires CLMUL and SSE2 instructions on this CPU"); |
| FLAG_SET_DEFAULT(UseGHASHIntrinsics, false); |
| } |
| |
| // ChaCha20 Intrinsics |
| // As long as the system supports AVX as a baseline we can do a |
| // SIMD-enabled block function. StubGenerator makes the determination |
| // based on the VM capabilities whether to use an AVX2 or AVX512-enabled |
| // version. |
| if (UseAVX >= 1) { |
| if (FLAG_IS_DEFAULT(UseChaCha20Intrinsics)) { |
| UseChaCha20Intrinsics = true; |
| } |
| } else if (UseChaCha20Intrinsics) { |
| if (!FLAG_IS_DEFAULT(UseChaCha20Intrinsics)) { |
| warning("ChaCha20 intrinsic requires AVX instructions"); |
| } |
| FLAG_SET_DEFAULT(UseChaCha20Intrinsics, false); |
| } |
| |
| // Kyber Intrinsics |
| // Currently we only have them for AVX512 |
| #ifdef _LP64 |
| if (supports_evex() && supports_avx512bw()) { |
| if (FLAG_IS_DEFAULT(UseKyberIntrinsics)) { |
| UseKyberIntrinsics = true; |
| } |
| } else |
| #endif |
| if (UseKyberIntrinsics) { |
| warning("Intrinsics for ML-KEM are not available on this CPU."); |
| FLAG_SET_DEFAULT(UseKyberIntrinsics, false); |
| } |
| |
| // Dilithium Intrinsics |
| // Currently we only have them for AVX512 |
| if (supports_evex() && supports_avx512bw()) { |
| if (FLAG_IS_DEFAULT(UseDilithiumIntrinsics)) { |
| UseDilithiumIntrinsics = true; |
| } |
| } else if (UseDilithiumIntrinsics) { |
| warning("Intrinsics for ML-DSA are not available on this CPU."); |
| FLAG_SET_DEFAULT(UseDilithiumIntrinsics, false); |
| } |
| |
| // Base64 Intrinsics (Check the condition for which the intrinsic will be active) |
| if (UseAVX >= 2) { |
| if (FLAG_IS_DEFAULT(UseBASE64Intrinsics)) { |
| UseBASE64Intrinsics = true; |
| } |
| } else if (UseBASE64Intrinsics) { |
| if (!FLAG_IS_DEFAULT(UseBASE64Intrinsics)) |
| warning("Base64 intrinsic requires EVEX instructions on this CPU"); |
| FLAG_SET_DEFAULT(UseBASE64Intrinsics, false); |
| } |
| |
| if (supports_fma()) { |
| if (FLAG_IS_DEFAULT(UseFMA)) { |
| UseFMA = true; |
| } |
| } else if (UseFMA) { |
| warning("FMA instructions are not available on this CPU"); |
| FLAG_SET_DEFAULT(UseFMA, false); |
| } |
| |
| if (FLAG_IS_DEFAULT(UseMD5Intrinsics)) { |
| UseMD5Intrinsics = true; |
| } |
| |
| if (supports_sha() || (supports_avx2() && supports_bmi2())) { |
| if (FLAG_IS_DEFAULT(UseSHA)) { |
| UseSHA = true; |
| } |
| } else if (UseSHA) { |
| warning("SHA instructions are not available on this CPU"); |
| FLAG_SET_DEFAULT(UseSHA, false); |
| } |
| |
| if (supports_sha() && supports_sse4_1() && UseSHA) { |
| if (FLAG_IS_DEFAULT(UseSHA1Intrinsics)) { |
| FLAG_SET_DEFAULT(UseSHA1Intrinsics, true); |
| } |
| } else if (UseSHA1Intrinsics) { |
| warning("Intrinsics for SHA-1 crypto hash functions not available on this CPU."); |
| FLAG_SET_DEFAULT(UseSHA1Intrinsics, false); |
| } |
| |
| if (supports_sse4_1() && UseSHA) { |
| if (FLAG_IS_DEFAULT(UseSHA256Intrinsics)) { |
| FLAG_SET_DEFAULT(UseSHA256Intrinsics, true); |
| } |
| } else if (UseSHA256Intrinsics) { |
| warning("Intrinsics for SHA-224 and SHA-256 crypto hash functions not available on this CPU."); |
| FLAG_SET_DEFAULT(UseSHA256Intrinsics, false); |
| } |
| |
| if (UseSHA && supports_avx2() && (supports_bmi2() || supports_sha512())) { |
| if (FLAG_IS_DEFAULT(UseSHA512Intrinsics)) { |
| FLAG_SET_DEFAULT(UseSHA512Intrinsics, true); |
| } |
| } else if (UseSHA512Intrinsics) { |
| warning("Intrinsics for SHA-384 and SHA-512 crypto hash functions not available on this CPU."); |
| FLAG_SET_DEFAULT(UseSHA512Intrinsics, false); |
| } |
| |
| if (supports_evex() && supports_avx512bw()) { |
| if (FLAG_IS_DEFAULT(UseSHA3Intrinsics)) { |
| UseSHA3Intrinsics = true; |
| } |
| } else if (UseSHA3Intrinsics) { |
| warning("Intrinsics for SHA3-224, SHA3-256, SHA3-384 and SHA3-512 crypto hash functions not available on this CPU."); |
| FLAG_SET_DEFAULT(UseSHA3Intrinsics, false); |
| } |
| |
| if (!(UseSHA1Intrinsics || UseSHA256Intrinsics || UseSHA512Intrinsics)) { |
| FLAG_SET_DEFAULT(UseSHA, false); |
| } |
| |
| #if COMPILER2_OR_JVMCI |
| int max_vector_size = 0; |
| if (UseAVX == 0 || !os_supports_avx_vectors()) { |
| // 16 byte vectors (in XMM) are supported with SSE2+ |
| max_vector_size = 16; |
| } else if (UseAVX == 1 || UseAVX == 2) { |
| // 32 bytes vectors (in YMM) are only supported with AVX+ |
| max_vector_size = 32; |
| } else if (UseAVX > 2) { |
| // 64 bytes vectors (in ZMM) are only supported with AVX 3 |
| max_vector_size = 64; |
| } |
| |
| int min_vector_size = 4; // We require MaxVectorSize to be at least 4 on 64bit |
| |
| if (!FLAG_IS_DEFAULT(MaxVectorSize)) { |
| if (MaxVectorSize < min_vector_size) { |
| warning("MaxVectorSize must be at least %i on this platform", min_vector_size); |
| FLAG_SET_DEFAULT(MaxVectorSize, min_vector_size); |
| } |
| if (MaxVectorSize > max_vector_size) { |
| warning("MaxVectorSize must be at most %i on this platform", max_vector_size); |
| FLAG_SET_DEFAULT(MaxVectorSize, max_vector_size); |
| } |
| if (!is_power_of_2(MaxVectorSize)) { |
| warning("MaxVectorSize must be a power of 2, setting to default: %i", max_vector_size); |
| FLAG_SET_DEFAULT(MaxVectorSize, max_vector_size); |
| } |
| } else { |
| // If default, use highest supported configuration |
| FLAG_SET_DEFAULT(MaxVectorSize, max_vector_size); |
| } |
| |
| #if defined(COMPILER2) && defined(ASSERT) |
| if (MaxVectorSize > 0) { |
| if (supports_avx() && PrintMiscellaneous && Verbose && TraceNewVectors) { |
| tty->print_cr("State of YMM registers after signal handle:"); |
| int nreg = 4; |
| const char* ymm_name[4] = {"0", "7", "8", "15"}; |
| for (int i = 0; i < nreg; i++) { |
| tty->print("YMM%s:", ymm_name[i]); |
| for (int j = 7; j >=0; j--) { |
| tty->print(" %x", _cpuid_info.ymm_save[i*8 + j]); |
| } |
| tty->cr(); |
| } |
| } |
| } |
| #endif // COMPILER2 && ASSERT |
| |
| if ((supports_avx512ifma() && supports_avx512vlbw()) || supports_avxifma()) { |
| if (FLAG_IS_DEFAULT(UsePoly1305Intrinsics)) { |
| FLAG_SET_DEFAULT(UsePoly1305Intrinsics, true); |
| } |
| } else if (UsePoly1305Intrinsics) { |
| warning("Intrinsics for Poly1305 crypto hash functions not available on this CPU."); |
| FLAG_SET_DEFAULT(UsePoly1305Intrinsics, false); |
| } |
| |
| if ((supports_avx512ifma() && supports_avx512vlbw()) || supports_avxifma()) { |
| if (FLAG_IS_DEFAULT(UseIntPolyIntrinsics)) { |
| FLAG_SET_DEFAULT(UseIntPolyIntrinsics, true); |
| } |
| } else if (UseIntPolyIntrinsics) { |
| warning("Intrinsics for Polynomial crypto functions not available on this CPU."); |
| FLAG_SET_DEFAULT(UseIntPolyIntrinsics, false); |
| } |
| |
| if (FLAG_IS_DEFAULT(UseMultiplyToLenIntrinsic)) { |
| UseMultiplyToLenIntrinsic = true; |
| } |
| if (FLAG_IS_DEFAULT(UseSquareToLenIntrinsic)) { |
| UseSquareToLenIntrinsic = true; |
| } |
| if (FLAG_IS_DEFAULT(UseMulAddIntrinsic)) { |
| UseMulAddIntrinsic = true; |
| } |
| if (FLAG_IS_DEFAULT(UseMontgomeryMultiplyIntrinsic)) { |
| UseMontgomeryMultiplyIntrinsic = true; |
| } |
| if (FLAG_IS_DEFAULT(UseMontgomerySquareIntrinsic)) { |
| UseMontgomerySquareIntrinsic = true; |
| } |
| #endif // COMPILER2_OR_JVMCI |
| |
| // On new cpus instructions which update whole XMM register should be used |
| // to prevent partial register stall due to dependencies on high half. |
| // |
| // UseXmmLoadAndClearUpper == true --> movsd(xmm, mem) |
| // UseXmmLoadAndClearUpper == false --> movlpd(xmm, mem) |
| // UseXmmRegToRegMoveAll == true --> movaps(xmm, xmm), movapd(xmm, xmm). |
| // UseXmmRegToRegMoveAll == false --> movss(xmm, xmm), movsd(xmm, xmm). |
| |
| |
| if (is_zx()) { // ZX cpus specific settings |
| if (FLAG_IS_DEFAULT(UseStoreImmI16)) { |
| UseStoreImmI16 = false; // don't use it on ZX cpus |
| } |
| if ((cpu_family() == 6) || (cpu_family() == 7)) { |
| if (FLAG_IS_DEFAULT(UseAddressNop)) { |
| // Use it on all ZX cpus |
| UseAddressNop = true; |
| } |
| } |
| if (FLAG_IS_DEFAULT(UseXmmLoadAndClearUpper)) { |
| UseXmmLoadAndClearUpper = true; // use movsd on all ZX cpus |
| } |
| if (FLAG_IS_DEFAULT(UseXmmRegToRegMoveAll)) { |
| if (supports_sse3()) { |
| UseXmmRegToRegMoveAll = true; // use movaps, movapd on new ZX cpus |
| } else { |
| UseXmmRegToRegMoveAll = false; |
| } |
| } |
| if (((cpu_family() == 6) || (cpu_family() == 7)) && supports_sse3()) { // new ZX cpus |
| #ifdef COMPILER2 |
| if (FLAG_IS_DEFAULT(MaxLoopPad)) { |
| // For new ZX cpus do the next optimization: |
| // don't align the beginning of a loop if there are enough instructions |
| // left (NumberOfLoopInstrToAlign defined in c2_globals.hpp) |
| // in current fetch line (OptoLoopAlignment) or the padding |
| // is big (> MaxLoopPad). |
| // Set MaxLoopPad to 11 for new ZX cpus to reduce number of |
| // generated NOP instructions. 11 is the largest size of one |
| // address NOP instruction '0F 1F' (see Assembler::nop(i)). |
| MaxLoopPad = 11; |
| } |
| #endif // COMPILER2 |
| if (FLAG_IS_DEFAULT(UseXMMForArrayCopy)) { |
| UseXMMForArrayCopy = true; // use SSE2 movq on new ZX cpus |
| } |
| if (supports_sse4_2()) { // new ZX cpus |
| if (FLAG_IS_DEFAULT(UseUnalignedLoadStores)) { |
| UseUnalignedLoadStores = true; // use movdqu on newest ZX cpus |
| } |
| } |
| if (supports_sse4_2()) { |
| if (FLAG_IS_DEFAULT(UseSSE42Intrinsics)) { |
| FLAG_SET_DEFAULT(UseSSE42Intrinsics, true); |
| } |
| } else { |
| if (UseSSE42Intrinsics && !FLAG_IS_DEFAULT(UseAESIntrinsics)) { |
| warning("SSE4.2 intrinsics require SSE4.2 instructions or higher. Intrinsics will be disabled."); |
| } |
| FLAG_SET_DEFAULT(UseSSE42Intrinsics, false); |
| } |
| } |
| |
| if (FLAG_IS_DEFAULT(AllocatePrefetchInstr) && supports_3dnow_prefetch()) { |
| FLAG_SET_DEFAULT(AllocatePrefetchInstr, 3); |
| } |
| } |
| |
| if (is_amd_family()) { // AMD cpus specific settings |
| if (supports_sse2() && FLAG_IS_DEFAULT(UseAddressNop)) { |
| // Use it on new AMD cpus starting from Opteron. |
| UseAddressNop = true; |
| } |
| if (supports_sse2() && FLAG_IS_DEFAULT(UseNewLongLShift)) { |
| // Use it on new AMD cpus starting from Opteron. |
| UseNewLongLShift = true; |
| } |
| if (FLAG_IS_DEFAULT(UseXmmLoadAndClearUpper)) { |
| if (supports_sse4a()) { |
| UseXmmLoadAndClearUpper = true; // use movsd only on '10h' Opteron |
| } else { |
| UseXmmLoadAndClearUpper = false; |
| } |
| } |
| if (FLAG_IS_DEFAULT(UseXmmRegToRegMoveAll)) { |
| if (supports_sse4a()) { |
| UseXmmRegToRegMoveAll = true; // use movaps, movapd only on '10h' |
| } else { |
| UseXmmRegToRegMoveAll = false; |
| } |
| } |
| if (FLAG_IS_DEFAULT(UseXmmI2F)) { |
| if (supports_sse4a()) { |
| UseXmmI2F = true; |
| } else { |
| UseXmmI2F = false; |
| } |
| } |
| if (FLAG_IS_DEFAULT(UseXmmI2D)) { |
| if (supports_sse4a()) { |
| UseXmmI2D = true; |
| } else { |
| UseXmmI2D = false; |
| } |
| } |
| if (supports_sse4_2()) { |
| if (FLAG_IS_DEFAULT(UseSSE42Intrinsics)) { |
| FLAG_SET_DEFAULT(UseSSE42Intrinsics, true); |
| } |
| } else { |
| if (UseSSE42Intrinsics && !FLAG_IS_DEFAULT(UseAESIntrinsics)) { |
| warning("SSE4.2 intrinsics require SSE4.2 instructions or higher. Intrinsics will be disabled."); |
| } |
| FLAG_SET_DEFAULT(UseSSE42Intrinsics, false); |
| } |
| |
| // some defaults for AMD family 15h |
| if (cpu_family() == 0x15) { |
| // On family 15h processors default is no sw prefetch |
| if (FLAG_IS_DEFAULT(AllocatePrefetchStyle)) { |
| FLAG_SET_DEFAULT(AllocatePrefetchStyle, 0); |
| } |
| // Also, if some other prefetch style is specified, default instruction type is PREFETCHW |
| if (FLAG_IS_DEFAULT(AllocatePrefetchInstr)) { |
| FLAG_SET_DEFAULT(AllocatePrefetchInstr, 3); |
| } |
| // On family 15h processors use XMM and UnalignedLoadStores for Array Copy |
| if (supports_sse2() && FLAG_IS_DEFAULT(UseXMMForArrayCopy)) { |
| FLAG_SET_DEFAULT(UseXMMForArrayCopy, true); |
| } |
| if (supports_sse2() && FLAG_IS_DEFAULT(UseUnalignedLoadStores)) { |
| FLAG_SET_DEFAULT(UseUnalignedLoadStores, true); |
| } |
| } |
| |
| #ifdef COMPILER2 |
| if (cpu_family() < 0x17 && MaxVectorSize > 16) { |
| // Limit vectors size to 16 bytes on AMD cpus < 17h. |
| FLAG_SET_DEFAULT(MaxVectorSize, 16); |
| } |
| #endif // COMPILER2 |
| |
| // Some defaults for AMD family >= 17h && Hygon family 18h |
| if (cpu_family() >= 0x17) { |
| // On family >=17h processors use XMM and UnalignedLoadStores |
| // for Array Copy |
| if (supports_sse2() && FLAG_IS_DEFAULT(UseXMMForArrayCopy)) { |
| FLAG_SET_DEFAULT(UseXMMForArrayCopy, true); |
| } |
| if (supports_sse2() && FLAG_IS_DEFAULT(UseUnalignedLoadStores)) { |
| FLAG_SET_DEFAULT(UseUnalignedLoadStores, true); |
| } |
| #ifdef COMPILER2 |
| if (supports_sse4_2() && FLAG_IS_DEFAULT(UseFPUForSpilling)) { |
| FLAG_SET_DEFAULT(UseFPUForSpilling, true); |
| } |
| #endif |
| } |
| } |
| |
| if (is_intel()) { // Intel cpus specific settings |
| if (FLAG_IS_DEFAULT(UseStoreImmI16)) { |
| UseStoreImmI16 = false; // don't use it on Intel cpus |
| } |
| if (is_intel_server_family() || cpu_family() == 15) { |
| if (FLAG_IS_DEFAULT(UseAddressNop)) { |
| // Use it on all Intel cpus starting from PentiumPro |
| UseAddressNop = true; |
| } |
| } |
| if (FLAG_IS_DEFAULT(UseXmmLoadAndClearUpper)) { |
| UseXmmLoadAndClearUpper = true; // use movsd on all Intel cpus |
| } |
| if (FLAG_IS_DEFAULT(UseXmmRegToRegMoveAll)) { |
| if (supports_sse3()) { |
| UseXmmRegToRegMoveAll = true; // use movaps, movapd on new Intel cpus |
| } else { |
| UseXmmRegToRegMoveAll = false; |
| } |
| } |
| if (is_intel_server_family() && supports_sse3()) { // New Intel cpus |
| #ifdef COMPILER2 |
| if (FLAG_IS_DEFAULT(MaxLoopPad)) { |
| // For new Intel cpus do the next optimization: |
| // don't align the beginning of a loop if there are enough instructions |
| // left (NumberOfLoopInstrToAlign defined in c2_globals.hpp) |
| // in current fetch line (OptoLoopAlignment) or the padding |
| // is big (> MaxLoopPad). |
| // Set MaxLoopPad to 11 for new Intel cpus to reduce number of |
| // generated NOP instructions. 11 is the largest size of one |
| // address NOP instruction '0F 1F' (see Assembler::nop(i)). |
| MaxLoopPad = 11; |
| } |
| #endif // COMPILER2 |
| |
| if (FLAG_IS_DEFAULT(UseXMMForArrayCopy)) { |
| UseXMMForArrayCopy = true; // use SSE2 movq on new Intel cpus |
| } |
| if ((supports_sse4_2() && supports_ht()) || supports_avx()) { // Newest Intel cpus |
| if (FLAG_IS_DEFAULT(UseUnalignedLoadStores)) { |
| UseUnalignedLoadStores = true; // use movdqu on newest Intel cpus |
| } |
| } |
| if (supports_sse4_2()) { |
| if (FLAG_IS_DEFAULT(UseSSE42Intrinsics)) { |
| FLAG_SET_DEFAULT(UseSSE42Intrinsics, true); |
| } |
| } else { |
| if (UseSSE42Intrinsics && !FLAG_IS_DEFAULT(UseAESIntrinsics)) { |
| warning("SSE4.2 intrinsics require SSE4.2 instructions or higher. Intrinsics will be disabled."); |
| } |
| FLAG_SET_DEFAULT(UseSSE42Intrinsics, false); |
| } |
| } |
| if (is_atom_family() || is_knights_family()) { |
| #ifdef COMPILER2 |
| if (FLAG_IS_DEFAULT(OptoScheduling)) { |
| OptoScheduling = true; |
| } |
| #endif |
| if (supports_sse4_2()) { // Silvermont |
| if (FLAG_IS_DEFAULT(UseUnalignedLoadStores)) { |
| UseUnalignedLoadStores = true; // use movdqu on newest Intel cpus |
| } |
| } |
| if (FLAG_IS_DEFAULT(UseIncDec)) { |
| FLAG_SET_DEFAULT(UseIncDec, false); |
| } |
| } |
| if (FLAG_IS_DEFAULT(AllocatePrefetchInstr) && supports_3dnow_prefetch()) { |
| FLAG_SET_DEFAULT(AllocatePrefetchInstr, 3); |
| } |
| #ifdef COMPILER2 |
| if (UseAVX > 2) { |
| if (FLAG_IS_DEFAULT(ArrayOperationPartialInlineSize) || |
| (!FLAG_IS_DEFAULT(ArrayOperationPartialInlineSize) && |
| ArrayOperationPartialInlineSize != 0 && |
| ArrayOperationPartialInlineSize != 16 && |
| ArrayOperationPartialInlineSize != 32 && |
| ArrayOperationPartialInlineSize != 64)) { |
| int inline_size = 0; |
| if (MaxVectorSize >= 64 && AVX3Threshold == 0) { |
| inline_size = 64; |
| } else if (MaxVectorSize >= 32) { |
| inline_size = 32; |
| } else if (MaxVectorSize >= 16) { |
| inline_size = 16; |
| } |
| if(!FLAG_IS_DEFAULT(ArrayOperationPartialInlineSize)) { |
| warning("Setting ArrayOperationPartialInlineSize as %d", inline_size); |
| } |
| ArrayOperationPartialInlineSize = inline_size; |
| } |
| |
| if (ArrayOperationPartialInlineSize > MaxVectorSize) { |
| ArrayOperationPartialInlineSize = MaxVectorSize >= 16 ? MaxVectorSize : 0; |
| if (ArrayOperationPartialInlineSize) { |
| warning("Setting ArrayOperationPartialInlineSize as MaxVectorSize=%zd", MaxVectorSize); |
| } else { |
| warning("Setting ArrayOperationPartialInlineSize as %zd", ArrayOperationPartialInlineSize); |
| } |
| } |
| } |
| #endif |
| } |
| |
| #ifdef COMPILER2 |
| if (FLAG_IS_DEFAULT(OptimizeFill)) { |
| if (MaxVectorSize < 32 || !VM_Version::supports_avx512vlbw()) { |
| OptimizeFill = false; |
| } |
| } |
| #endif |
| |
| if (UseSSE42Intrinsics) { |
| if (FLAG_IS_DEFAULT(UseVectorizedMismatchIntrinsic)) { |
| UseVectorizedMismatchIntrinsic = true; |
| } |
| } else if (UseVectorizedMismatchIntrinsic) { |
| if (!FLAG_IS_DEFAULT(UseVectorizedMismatchIntrinsic)) |
| warning("vectorizedMismatch intrinsics are not available on this CPU"); |
| FLAG_SET_DEFAULT(UseVectorizedMismatchIntrinsic, false); |
| } |
| if (UseAVX >= 2) { |
| FLAG_SET_DEFAULT(UseVectorizedHashCodeIntrinsic, true); |
| } else if (UseVectorizedHashCodeIntrinsic) { |
| if (!FLAG_IS_DEFAULT(UseVectorizedHashCodeIntrinsic)) |
| warning("vectorizedHashCode intrinsics are not available on this CPU"); |
| FLAG_SET_DEFAULT(UseVectorizedHashCodeIntrinsic, false); |
| } |
| |
| // Use count leading zeros count instruction if available. |
| if (supports_lzcnt()) { |
| if (FLAG_IS_DEFAULT(UseCountLeadingZerosInstruction)) { |
| UseCountLeadingZerosInstruction = true; |
| } |
| } else if (UseCountLeadingZerosInstruction) { |
| warning("lzcnt instruction is not available on this CPU"); |
| FLAG_SET_DEFAULT(UseCountLeadingZerosInstruction, false); |
| } |
| |
| // Use count trailing zeros instruction if available |
| if (supports_bmi1()) { |
| // tzcnt does not require VEX prefix |
| if (FLAG_IS_DEFAULT(UseCountTrailingZerosInstruction)) { |
| if (!UseBMI1Instructions && !FLAG_IS_DEFAULT(UseBMI1Instructions)) { |
| // Don't use tzcnt if BMI1 is switched off on command line. |
| UseCountTrailingZerosInstruction = false; |
| } else { |
| UseCountTrailingZerosInstruction = true; |
| } |
| } |
| } else if (UseCountTrailingZerosInstruction) { |
| warning("tzcnt instruction is not available on this CPU"); |
| FLAG_SET_DEFAULT(UseCountTrailingZerosInstruction, false); |
| } |
| |
| // BMI instructions (except tzcnt) use an encoding with VEX prefix. |
| // VEX prefix is generated only when AVX > 0. |
| if (supports_bmi1() && supports_avx()) { |
| if (FLAG_IS_DEFAULT(UseBMI1Instructions)) { |
| UseBMI1Instructions = true; |
| } |
| } else if (UseBMI1Instructions) { |
| warning("BMI1 instructions are not available on this CPU (AVX is also required)"); |
| FLAG_SET_DEFAULT(UseBMI1Instructions, false); |
| } |
| |
| if (supports_bmi2() && supports_avx()) { |
| if (FLAG_IS_DEFAULT(UseBMI2Instructions)) { |
| UseBMI2Instructions = true; |
| } |
| } else if (UseBMI2Instructions) { |
| warning("BMI2 instructions are not available on this CPU (AVX is also required)"); |
| FLAG_SET_DEFAULT(UseBMI2Instructions, false); |
| } |
| |
| // Use population count instruction if available. |
| if (supports_popcnt()) { |
| if (FLAG_IS_DEFAULT(UsePopCountInstruction)) { |
| UsePopCountInstruction = true; |
| } |
| } else if (UsePopCountInstruction) { |
| warning("POPCNT instruction is not available on this CPU"); |
| FLAG_SET_DEFAULT(UsePopCountInstruction, false); |
| } |
| |
| // Use fast-string operations if available. |
| if (supports_erms()) { |
| if (FLAG_IS_DEFAULT(UseFastStosb)) { |
| UseFastStosb = true; |
| } |
| } else if (UseFastStosb) { |
| warning("fast-string operations are not available on this CPU"); |
| FLAG_SET_DEFAULT(UseFastStosb, false); |
| } |
| |
| // For AMD Processors use XMM/YMM MOVDQU instructions |
| // for Object Initialization as default |
| if (is_amd() && cpu_family() >= 0x19) { |
| if (FLAG_IS_DEFAULT(UseFastStosb)) { |
| UseFastStosb = false; |
| } |
| } |
| |
| #ifdef COMPILER2 |
| if (is_intel() && MaxVectorSize > 16) { |
| if (FLAG_IS_DEFAULT(UseFastStosb)) { |
| UseFastStosb = false; |
| } |
| } |
| #endif |
| |
| // Use XMM/YMM MOVDQU instruction for Object Initialization |
| if (!UseFastStosb && UseUnalignedLoadStores) { |
| if (FLAG_IS_DEFAULT(UseXMMForObjInit)) { |
| UseXMMForObjInit = true; |
| } |
| } else if (UseXMMForObjInit) { |
| warning("UseXMMForObjInit requires SSE2 and unaligned load/stores. Feature is switched off."); |
| FLAG_SET_DEFAULT(UseXMMForObjInit, false); |
| } |
| |
| #ifdef COMPILER2 |
| if (FLAG_IS_DEFAULT(AlignVector)) { |
| // Modern processors allow misaligned memory operations for vectors. |
| AlignVector = !UseUnalignedLoadStores; |
| } |
| #endif // COMPILER2 |
| |
| if (FLAG_IS_DEFAULT(AllocatePrefetchInstr)) { |
| if (AllocatePrefetchInstr == 3 && !supports_3dnow_prefetch()) { |
| FLAG_SET_DEFAULT(AllocatePrefetchInstr, 0); |
| } else if (!supports_sse() && supports_3dnow_prefetch()) { |
| FLAG_SET_DEFAULT(AllocatePrefetchInstr, 3); |
| } |
| } |
| |
| // Allocation prefetch settings |
| int cache_line_size = checked_cast<int>(prefetch_data_size()); |
| if (FLAG_IS_DEFAULT(AllocatePrefetchStepSize) && |
| (cache_line_size > AllocatePrefetchStepSize)) { |
| FLAG_SET_DEFAULT(AllocatePrefetchStepSize, cache_line_size); |
| } |
| |
| if ((AllocatePrefetchDistance == 0) && (AllocatePrefetchStyle != 0)) { |
| assert(!FLAG_IS_DEFAULT(AllocatePrefetchDistance), "default value should not be 0"); |
| if (!FLAG_IS_DEFAULT(AllocatePrefetchStyle)) { |
| warning("AllocatePrefetchDistance is set to 0 which disable prefetching. Ignoring AllocatePrefetchStyle flag."); |
| } |
| FLAG_SET_DEFAULT(AllocatePrefetchStyle, 0); |
| } |
| |
| if (FLAG_IS_DEFAULT(AllocatePrefetchDistance)) { |
| bool use_watermark_prefetch = (AllocatePrefetchStyle == 2); |
| FLAG_SET_DEFAULT(AllocatePrefetchDistance, allocate_prefetch_distance(use_watermark_prefetch)); |
| } |
| |
| if (is_intel() && is_intel_server_family() && supports_sse3()) { |
| if (FLAG_IS_DEFAULT(AllocatePrefetchLines) && |
| supports_sse4_2() && supports_ht()) { // Nehalem based cpus |
| FLAG_SET_DEFAULT(AllocatePrefetchLines, 4); |
| } |
| #ifdef COMPILER2 |
| if (FLAG_IS_DEFAULT(UseFPUForSpilling) && supports_sse4_2()) { |
| FLAG_SET_DEFAULT(UseFPUForSpilling, true); |
| } |
| #endif |
| } |
| |
| if (is_zx() && ((cpu_family() == 6) || (cpu_family() == 7)) && supports_sse4_2()) { |
| #ifdef COMPILER2 |
| if (FLAG_IS_DEFAULT(UseFPUForSpilling)) { |
| FLAG_SET_DEFAULT(UseFPUForSpilling, true); |
| } |
| #endif |
| } |
| |
| // Prefetch settings |
| |
| // Prefetch interval for gc copy/scan == 9 dcache lines. Derived from |
| // 50-warehouse specjbb runs on a 2-way 1.8ghz opteron using a 4gb heap. |
| // Tested intervals from 128 to 2048 in increments of 64 == one cache line. |
| // 256 bytes (4 dcache lines) was the nearest runner-up to 576. |
| |
| // gc copy/scan is disabled if prefetchw isn't supported, because |
| // Prefetch::write emits an inlined prefetchw on Linux. |
| // Do not use the 3dnow prefetchw instruction. It isn't supported on em64t. |
| // The used prefetcht0 instruction works for both amd64 and em64t. |
| |
| if (FLAG_IS_DEFAULT(PrefetchCopyIntervalInBytes)) { |
| FLAG_SET_DEFAULT(PrefetchCopyIntervalInBytes, 576); |
| } |
| if (FLAG_IS_DEFAULT(PrefetchScanIntervalInBytes)) { |
| FLAG_SET_DEFAULT(PrefetchScanIntervalInBytes, 576); |
| } |
| |
| if (FLAG_IS_DEFAULT(ContendedPaddingWidth) && |
| (cache_line_size > ContendedPaddingWidth)) |
| ContendedPaddingWidth = cache_line_size; |
| |
| // This machine allows unaligned memory accesses |
| if (FLAG_IS_DEFAULT(UseUnalignedAccesses)) { |
| FLAG_SET_DEFAULT(UseUnalignedAccesses, true); |
| } |
| |
| #ifndef PRODUCT |
| if (log_is_enabled(Info, os, cpu)) { |
| LogStream ls(Log(os, cpu)::info()); |
| outputStream* log = &ls; |
| log->print_cr("Logical CPUs per core: %u", |
| logical_processors_per_package()); |
| log->print_cr("L1 data cache line size: %u", L1_data_cache_line_size()); |
| log->print("UseSSE=%d", UseSSE); |
| if (UseAVX > 0) { |
| log->print(" UseAVX=%d", UseAVX); |
| } |
| if (UseAES) { |
| log->print(" UseAES=1"); |
| } |
| #ifdef COMPILER2 |
| if (MaxVectorSize > 0) { |
| log->print(" MaxVectorSize=%d", (int) MaxVectorSize); |
| } |
| #endif |
| log->cr(); |
| log->print("Allocation"); |
| if (AllocatePrefetchStyle <= 0) { |
| log->print_cr(": no prefetching"); |
| } else { |
| log->print(" prefetching: "); |
| if (AllocatePrefetchInstr == 0) { |
| log->print("PREFETCHNTA"); |
| } else if (AllocatePrefetchInstr == 1) { |
| log->print("PREFETCHT0"); |
| } else if (AllocatePrefetchInstr == 2) { |
| log->print("PREFETCHT2"); |
| } else if (AllocatePrefetchInstr == 3) { |
| log->print("PREFETCHW"); |
| } |
| if (AllocatePrefetchLines > 1) { |
| log->print_cr(" at distance %d, %d lines of %d bytes", AllocatePrefetchDistance, AllocatePrefetchLines, AllocatePrefetchStepSize); |
| } else { |
| log->print_cr(" at distance %d, one line of %d bytes", AllocatePrefetchDistance, AllocatePrefetchStepSize); |
| } |
| } |
| |
| if (PrefetchCopyIntervalInBytes > 0) { |
| log->print_cr("PrefetchCopyIntervalInBytes %d", (int) PrefetchCopyIntervalInBytes); |
| } |
| if (PrefetchScanIntervalInBytes > 0) { |
| log->print_cr("PrefetchScanIntervalInBytes %d", (int) PrefetchScanIntervalInBytes); |
| } |
| if (ContendedPaddingWidth > 0) { |
| log->print_cr("ContendedPaddingWidth %d", (int) ContendedPaddingWidth); |
| } |
| } |
| #endif // !PRODUCT |
| if (FLAG_IS_DEFAULT(UseSignumIntrinsic)) { |
| FLAG_SET_DEFAULT(UseSignumIntrinsic, true); |
| } |
| if (FLAG_IS_DEFAULT(UseCopySignIntrinsic)) { |
| FLAG_SET_DEFAULT(UseCopySignIntrinsic, true); |
| } |
| } |
| |
| void VM_Version::print_platform_virtualization_info(outputStream* st) { |
| VirtualizationType vrt = VM_Version::get_detected_virtualization(); |
| if (vrt == XenHVM) { |
| st->print_cr("Xen hardware-assisted virtualization detected"); |
| } else if (vrt == KVM) { |
| st->print_cr("KVM virtualization detected"); |
| } else if (vrt == VMWare) { |
| st->print_cr("VMWare virtualization detected"); |
| VirtualizationSupport::print_virtualization_info(st); |
| } else if (vrt == HyperV) { |
| st->print_cr("Hyper-V virtualization detected"); |
| } else if (vrt == HyperVRole) { |
| st->print_cr("Hyper-V role detected"); |
| } |
| } |
| |
| bool VM_Version::compute_has_intel_jcc_erratum() { |
| if (!is_intel_family_core()) { |
| // Only Intel CPUs are affected. |
| return false; |
| } |
| // The following table of affected CPUs is based on the following document released by Intel: |
| // https://www.intel.com/content/dam/support/us/en/documents/processors/mitigations-jump-conditional-code-erratum.pdf |
| switch (_model) { |
| case 0x8E: |
| // 06_8EH | 9 | 8th Generation Intel(R) Core(TM) Processor Family based on microarchitecture code name Amber Lake Y |
| // 06_8EH | 9 | 7th Generation Intel(R) Core(TM) Processor Family based on microarchitecture code name Kaby Lake U |
| // 06_8EH | 9 | 7th Generation Intel(R) Core(TM) Processor Family based on microarchitecture code name Kaby Lake U 23e |
| // 06_8EH | 9 | 7th Generation Intel(R) Core(TM) Processor Family based on microarchitecture code name Kaby Lake Y |
| // 06_8EH | A | 8th Generation Intel(R) Core(TM) Processor Family based on microarchitecture code name Coffee Lake U43e |
| // 06_8EH | B | 8th Generation Intel(R) Core(TM) Processors based on microarchitecture code name Whiskey Lake U |
| // 06_8EH | C | 8th Generation Intel(R) Core(TM) Processor Family based on microarchitecture code name Amber Lake Y |
| // 06_8EH | C | 10th Generation Intel(R) Core(TM) Processor Family based on microarchitecture code name Comet Lake U42 |
| // 06_8EH | C | 8th Generation Intel(R) Core(TM) Processors based on microarchitecture code name Whiskey Lake U |
| return _stepping == 0x9 || _stepping == 0xA || _stepping == 0xB || _stepping == 0xC; |
| case 0x4E: |
| // 06_4E | 3 | 6th Generation Intel(R) Core(TM) Processors based on microarchitecture code name Skylake U |
| // 06_4E | 3 | 6th Generation Intel(R) Core(TM) Processor Family based on microarchitecture code name Skylake U23e |
| // 06_4E | 3 | 6th Generation Intel(R) Core(TM) Processors based on microarchitecture code name Skylake Y |
| return _stepping == 0x3; |
| case 0x55: |
| // 06_55H | 4 | Intel(R) Xeon(R) Processor D Family based on microarchitecture code name Skylake D, Bakerville |
| // 06_55H | 4 | Intel(R) Xeon(R) Scalable Processors based on microarchitecture code name Skylake Server |
| // 06_55H | 4 | Intel(R) Xeon(R) Processor W Family based on microarchitecture code name Skylake W |
| // 06_55H | 4 | Intel(R) Core(TM) X-series Processors based on microarchitecture code name Skylake X |
| // 06_55H | 4 | Intel(R) Xeon(R) Processor E3 v5 Family based on microarchitecture code name Skylake Xeon E3 |
| // 06_55 | 7 | 2nd Generation Intel(R) Xeon(R) Scalable Processors based on microarchitecture code name Cascade Lake (server) |
| return _stepping == 0x4 || _stepping == 0x7; |
| case 0x5E: |
| // 06_5E | 3 | 6th Generation Intel(R) Core(TM) Processor Family based on microarchitecture code name Skylake H |
| // 06_5E | 3 | 6th Generation Intel(R) Core(TM) Processor Family based on microarchitecture code name Skylake S |
| return _stepping == 0x3; |
| case 0x9E: |
| // 06_9EH | 9 | 8th Generation Intel(R) Core(TM) Processor Family based on microarchitecture code name Kaby Lake G |
| // 06_9EH | 9 | 7th Generation Intel(R) Core(TM) Processor Family based on microarchitecture code name Kaby Lake H |
| // 06_9EH | 9 | 7th Generation Intel(R) Core(TM) Processor Family based on microarchitecture code name Kaby Lake S |
| // 06_9EH | 9 | Intel(R) Core(TM) X-series Processors based on microarchitecture code name Kaby Lake X |
| // 06_9EH | 9 | Intel(R) Xeon(R) Processor E3 v6 Family Kaby Lake Xeon E3 |
| // 06_9EH | A | 8th Generation Intel(R) Core(TM) Processor Family based on microarchitecture code name Coffee Lake H |
| // 06_9EH | A | 8th Generation Intel(R) Core(TM) Processor Family based on microarchitecture code name Coffee Lake S |
| // 06_9EH | A | 8th Generation Intel(R) Core(TM) Processor Family based on microarchitecture code name Coffee Lake S (6+2) x/KBP |
| // 06_9EH | A | Intel(R) Xeon(R) Processor E Family based on microarchitecture code name Coffee Lake S (6+2) |
| // 06_9EH | A | Intel(R) Xeon(R) Processor E Family based on microarchitecture code name Coffee Lake S (4+2) |
| // 06_9EH | B | 8th Generation Intel(R) Core(TM) Processor Family based on microarchitecture code name Coffee Lake S (4+2) |
| // 06_9EH | B | Intel(R) Celeron(R) Processor G Series based on microarchitecture code name Coffee Lake S (4+2) |
| // 06_9EH | D | 9th Generation Intel(R) Core(TM) Processor Family based on microarchitecturecode name Coffee Lake H (8+2) |
| // 06_9EH | D | 9th Generation Intel(R) Core(TM) Processor Family based on microarchitecture code name Coffee Lake S (8+2) |
| return _stepping == 0x9 || _stepping == 0xA || _stepping == 0xB || _stepping == 0xD; |
| case 0xA5: |
| // Not in Intel documentation. |
| // 06_A5H | | 10th Generation Intel(R) Core(TM) Processor Family based on microarchitecture code name Comet Lake S/H |
| return true; |
| case 0xA6: |
| // 06_A6H | 0 | 10th Generation Intel(R) Core(TM) Processor Family based on microarchitecture code name Comet Lake U62 |
| return _stepping == 0x0; |
| case 0xAE: |
| // 06_AEH | A | 8th Generation Intel(R) Core(TM) Processor Family based on microarchitecture code name Kaby Lake Refresh U (4+2) |
| return _stepping == 0xA; |
| default: |
| // If we are running on another intel machine not recognized in the table, we are okay. |
| return false; |
| } |
| } |
| |
| // On Xen, the cpuid instruction returns |
| // eax / registers[0]: Version of Xen |
| // ebx / registers[1]: chars 'XenV' |
| // ecx / registers[2]: chars 'MMXe' |
| // edx / registers[3]: chars 'nVMM' |
| // |
| // On KVM / VMWare / MS Hyper-V, the cpuid instruction returns |
| // ebx / registers[1]: chars 'KVMK' / 'VMwa' / 'Micr' |
| // ecx / registers[2]: chars 'VMKV' / 'reVM' / 'osof' |
| // edx / registers[3]: chars 'M' / 'ware' / 't Hv' |
| // |
| // more information : |
| // https://kb.vmware.com/s/article/1009458 |
| // |
| void VM_Version::check_virtualizations() { |
| uint32_t registers[4] = {0}; |
| char signature[13] = {0}; |
| |
| // Xen cpuid leaves can be found 0x100 aligned boundary starting |
| // from 0x40000000 until 0x40010000. |
| // https://lists.linuxfoundation.org/pipermail/virtualization/2012-May/019974.html |
| for (int leaf = 0x40000000; leaf < 0x40010000; leaf += 0x100) { |
| detect_virt_stub(leaf, registers); |
| memcpy(signature, ®isters[1], 12); |
| |
| if (strncmp("VMwareVMware", signature, 12) == 0) { |
| Abstract_VM_Version::_detected_virtualization = VMWare; |
| // check for extended metrics from guestlib |
| VirtualizationSupport::initialize(); |
| } else if (strncmp("Microsoft Hv", signature, 12) == 0) { |
| Abstract_VM_Version::_detected_virtualization = HyperV; |
| #ifdef _WINDOWS |
| // CPUID leaf 0x40000007 is available to the root partition only. |
| // See Hypervisor Top Level Functional Specification section 2.4.8 for more details. |
| // https://github.com/MicrosoftDocs/Virtualization-Documentation/raw/master/tlfs/Hypervisor%20Top%20Level%20Functional%20Specification%20v6.0b.pdf |
| detect_virt_stub(0x40000007, registers); |
| if ((registers[0] != 0x0) || |
| (registers[1] != 0x0) || |
| (registers[2] != 0x0) || |
| (registers[3] != 0x0)) { |
| Abstract_VM_Version::_detected_virtualization = HyperVRole; |
| } |
| #endif |
| } else if (strncmp("KVMKVMKVM", signature, 9) == 0) { |
| Abstract_VM_Version::_detected_virtualization = KVM; |
| } else if (strncmp("XenVMMXenVMM", signature, 12) == 0) { |
| Abstract_VM_Version::_detected_virtualization = XenHVM; |
| } |
| } |
| } |
| |
| #ifdef COMPILER2 |
| // Determine if it's running on Cascade Lake using default options. |
| bool VM_Version::is_default_intel_cascade_lake() { |
| return FLAG_IS_DEFAULT(UseAVX) && |
| FLAG_IS_DEFAULT(MaxVectorSize) && |
| UseAVX > 2 && |
| is_intel_cascade_lake(); |
| } |
| #endif |
| |
| bool VM_Version::is_intel_cascade_lake() { |
| return is_intel_skylake() && _stepping >= 5; |
| } |
| |
| // avx3_threshold() sets the threshold at which 64-byte instructions are used |
| // for implementing the array copy and clear operations. |
| // The Intel platforms that supports the serialize instruction |
| // has improved implementation of 64-byte load/stores and so the default |
| // threshold is set to 0 for these platforms. |
| int VM_Version::avx3_threshold() { |
| return (is_intel_server_family() && |
| supports_serialize() && |
| FLAG_IS_DEFAULT(AVX3Threshold)) ? 0 : AVX3Threshold; |
| } |
| |
| void VM_Version::clear_apx_test_state() { |
| clear_apx_test_state_stub(); |
| } |
| |
| 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) { |
| vm_exit_during_initialization("Unable to allocate stub for VM_Version"); |
| } |
| CodeBuffer c(stub_blob); |
| VM_Version_StubGenerator g(&c); |
| |
| get_cpu_info_stub = CAST_TO_FN_PTR(get_cpu_info_stub_t, |
| g.generate_get_cpu_info()); |
| detect_virt_stub = CAST_TO_FN_PTR(detect_virt_stub_t, |
| g.generate_detect_virt()); |
| clear_apx_test_state_stub = CAST_TO_FN_PTR(clear_apx_test_state_t, |
| g.clear_apx_test_state()); |
| get_processor_features(); |
| |
| Assembler::precompute_instructions(); |
| |
| if (VM_Version::supports_hv()) { // Supports hypervisor |
| check_virtualizations(); |
| } |
| _vm_version_initialized = true; |
| } |
| |
| typedef enum { |
| CPU_FAMILY_8086_8088 = 0, |
| CPU_FAMILY_INTEL_286 = 2, |
| CPU_FAMILY_INTEL_386 = 3, |
| CPU_FAMILY_INTEL_486 = 4, |
| CPU_FAMILY_PENTIUM = 5, |
| CPU_FAMILY_PENTIUMPRO = 6, // Same family several models |
| CPU_FAMILY_PENTIUM_4 = 0xF |
| } FamilyFlag; |
| |
| typedef enum { |
| RDTSCP_FLAG = 0x08000000, // bit 27 |
| INTEL64_FLAG = 0x20000000 // bit 29 |
| } _featureExtendedEdxFlag; |
| |
| typedef enum { |
| FPU_FLAG = 0x00000001, |
| VME_FLAG = 0x00000002, |
| DE_FLAG = 0x00000004, |
| PSE_FLAG = 0x00000008, |
| TSC_FLAG = 0x00000010, |
| MSR_FLAG = 0x00000020, |
| PAE_FLAG = 0x00000040, |
| MCE_FLAG = 0x00000080, |
| CX8_FLAG = 0x00000100, |
| APIC_FLAG = 0x00000200, |
| SEP_FLAG = 0x00000800, |
| MTRR_FLAG = 0x00001000, |
| PGE_FLAG = 0x00002000, |
| MCA_FLAG = 0x00004000, |
| CMOV_FLAG = 0x00008000, |
| PAT_FLAG = 0x00010000, |
| PSE36_FLAG = 0x00020000, |
| PSNUM_FLAG = 0x00040000, |
| CLFLUSH_FLAG = 0x00080000, |
| DTS_FLAG = 0x00200000, |
| ACPI_FLAG = 0x00400000, |
| MMX_FLAG = 0x00800000, |
| FXSR_FLAG = 0x01000000, |
| SSE_FLAG = 0x02000000, |
| SSE2_FLAG = 0x04000000, |
| SS_FLAG = 0x08000000, |
| HTT_FLAG = 0x10000000, |
| TM_FLAG = 0x20000000 |
| } FeatureEdxFlag; |
| |
| static BufferBlob* cpuid_brand_string_stub_blob; |
| static const int cpuid_brand_string_stub_size = 550; |
| |
| extern "C" { |
| typedef void (*getCPUIDBrandString_stub_t)(void*); |
| } |
| |
| static getCPUIDBrandString_stub_t getCPUIDBrandString_stub = nullptr; |
| |
| // VM_Version statics |
| enum { |
| ExtendedFamilyIdLength_INTEL = 16, |
| ExtendedFamilyIdLength_AMD = 24 |
| }; |
| |
| const size_t VENDOR_LENGTH = 13; |
| const size_t CPU_EBS_MAX_LENGTH = (3 * 4 * 4 + 1); |
| static char* _cpu_brand_string = nullptr; |
| static int64_t _max_qualified_cpu_frequency = 0; |
| |
| static int _no_of_threads = 0; |
| static int _no_of_cores = 0; |
| |
| const char* const _family_id_intel[ExtendedFamilyIdLength_INTEL] = { |
| "8086/8088", |
| "", |
| "286", |
| "386", |
| "486", |
| "Pentium", |
| "Pentium Pro", //or Pentium-M/Woodcrest depending on model |
| "", |
| "", |
| "", |
| "", |
| "", |
| "", |
| "", |
| "", |
| "Pentium 4" |
| }; |
| |
| const char* const _family_id_amd[ExtendedFamilyIdLength_AMD] = { |
| "", |
| "", |
| "", |
| "", |
| "5x86", |
| "K5/K6", |
| "Athlon/AthlonXP", |
| "", |
| "", |
| "", |
| "", |
| "", |
| "", |
| "", |
| "", |
| "Opteron/Athlon64", |
| "Opteron QC/Phenom", // Barcelona et.al. |
| "", |
| "", |
| "", |
| "", |
| "", |
| "", |
| "Zen" |
| }; |
| // Partially from Intel 64 and IA-32 Architecture Software Developer's Manual, |
| // September 2013, Vol 3C Table 35-1 |
| const char* const _model_id_pentium_pro[] = { |
| "", |
| "Pentium Pro", |
| "", |
| "Pentium II model 3", |
| "", |
| "Pentium II model 5/Xeon/Celeron", |
| "Celeron", |
| "Pentium III/Pentium III Xeon", |
| "Pentium III/Pentium III Xeon", |
| "Pentium M model 9", // Yonah |
| "Pentium III, model A", |
| "Pentium III, model B", |
| "", |
| "Pentium M model D", // Dothan |
| "", |
| "Core 2", // 0xf Woodcrest/Conroe/Merom/Kentsfield/Clovertown |
| "", |
| "", |
| "", |
| "", |
| "", |
| "", |
| "Celeron", // 0x16 Celeron 65nm |
| "Core 2", // 0x17 Penryn / Harpertown |
| "", |
| "", |
| "Core i7", // 0x1A CPU_MODEL_NEHALEM_EP |
| "Atom", // 0x1B Z5xx series Silverthorn |
| "", |
| "Core 2", // 0x1D Dunnington (6-core) |
| "Nehalem", // 0x1E CPU_MODEL_NEHALEM |
| "", |
| "", |
| "", |
| "", |
| "", |
| "", |
| "Westmere", // 0x25 CPU_MODEL_WESTMERE |
| "", |
| "", |
| "", // 0x28 |
| "", |
| "Sandy Bridge", // 0x2a "2nd Generation Intel Core i7, i5, i3" |
| "", |
| "Westmere-EP", // 0x2c CPU_MODEL_WESTMERE_EP |
| "Sandy Bridge-EP", // 0x2d CPU_MODEL_SANDYBRIDGE_EP |
| "Nehalem-EX", // 0x2e CPU_MODEL_NEHALEM_EX |
| "Westmere-EX", // 0x2f CPU_MODEL_WESTMERE_EX |
| "", |
| "", |
| "", |
| "", |
| "", |
| "", |
| "", |
| "", |
| "", |
| "", |
| "Ivy Bridge", // 0x3a |
| "", |
| "Haswell", // 0x3c "4th Generation Intel Core Processor" |
| "", // 0x3d "Next Generation Intel Core Processor" |
| "Ivy Bridge-EP", // 0x3e "Next Generation Intel Xeon Processor E7 Family" |
| "", // 0x3f "Future Generation Intel Xeon Processor" |
| "", |
| "", |
| "", |
| "", |
| "", |
| "Haswell", // 0x45 "4th Generation Intel Core Processor" |
| "Haswell", // 0x46 "4th Generation Intel Core Processor" |
| nullptr |
| }; |
| |
| /* Brand ID is for back compatibility |
| * Newer CPUs uses the extended brand string */ |
| const char* const _brand_id[] = { |
| "", |
| "Celeron processor", |
| "Pentium III processor", |
| "Intel Pentium III Xeon processor", |
| "", |
| "", |
| "", |
| "", |
| "Intel Pentium 4 processor", |
| nullptr |
| }; |
| |
| |
| const char* const _feature_edx_id[] = { |
| "On-Chip FPU", |
| "Virtual Mode Extensions", |
| "Debugging Extensions", |
| "Page Size Extensions", |
| "Time Stamp Counter", |
| "Model Specific Registers", |
| "Physical Address Extension", |
| "Machine Check Exceptions", |
| "CMPXCHG8B Instruction", |
| "On-Chip APIC", |
| "", |
| "Fast System Call", |
| "Memory Type Range Registers", |
| "Page Global Enable", |
| "Machine Check Architecture", |
| "Conditional Mov Instruction", |
| "Page Attribute Table", |
| "36-bit Page Size Extension", |
| "Processor Serial Number", |
| "CLFLUSH Instruction", |
| "", |
| "Debug Trace Store feature", |
| "ACPI registers in MSR space", |
| "Intel Architecture MMX Technology", |
| "Fast Float Point Save and Restore", |
| "Streaming SIMD extensions", |
| "Streaming SIMD extensions 2", |
| "Self-Snoop", |
| "Hyper Threading", |
| "Thermal Monitor", |
| "", |
| "Pending Break Enable" |
| }; |
| |
| const char* const _feature_extended_edx_id[] = { |
| "", |
| "", |
| "", |
| "", |
| "", |
| "", |
| "", |
| "", |
| "", |
| "", |
| "", |
| "SYSCALL/SYSRET", |
| "", |
| "", |
| "", |
| "", |
| "", |
| "", |
| "", |
| "", |
| "Execute Disable Bit", |
| "", |
| "", |
| "", |
| "", |
| "", |
| "", |
| "RDTSCP", |
| "", |
| "Intel 64 Architecture", |
| "", |
| "" |
| }; |
| |
| const char* const _feature_ecx_id[] = { |
| "Streaming SIMD Extensions 3", |
| "PCLMULQDQ", |
| "64-bit DS Area", |
| "MONITOR/MWAIT instructions", |
| "CPL Qualified Debug Store", |
| "Virtual Machine Extensions", |
| "Safer Mode Extensions", |
| "Enhanced Intel SpeedStep technology", |
| "Thermal Monitor 2", |
| "Supplemental Streaming SIMD Extensions 3", |
| "L1 Context ID", |
| "", |
| "Fused Multiply-Add", |
| "CMPXCHG16B", |
| "xTPR Update Control", |
| "Perfmon and Debug Capability", |
| "", |
| "Process-context identifiers", |
| "Direct Cache Access", |
| "Streaming SIMD extensions 4.1", |
| "Streaming SIMD extensions 4.2", |
| "x2APIC", |
| "MOVBE", |
| "Popcount instruction", |
| "TSC-Deadline", |
| "AESNI", |
| "XSAVE", |
| "OSXSAVE", |
| "AVX", |
| "F16C", |
| "RDRAND", |
| "" |
| }; |
| |
| const char* const _feature_extended_ecx_id[] = { |
| "LAHF/SAHF instruction support", |
| "Core multi-processor legacy mode", |
| "", |
| "", |
| "", |
| "Advanced Bit Manipulations: LZCNT", |
| "SSE4A: MOVNTSS, MOVNTSD, EXTRQ, INSERTQ", |
| "Misaligned SSE mode", |
| "", |
| "", |
| "", |
| "", |
| "", |
| "", |
| "", |
| "", |
| "", |
| "", |
| "", |
| "", |
| "", |
| "", |
| "", |
| "", |
| "", |
| "", |
| "", |
| "", |
| "", |
| "", |
| "", |
| "" |
| }; |
| |
| void VM_Version::initialize_tsc(void) { |
| ResourceMark rm; |
| |
| cpuid_brand_string_stub_blob = BufferBlob::create("getCPUIDBrandString_stub", cpuid_brand_string_stub_size); |
| if (cpuid_brand_string_stub_blob == nullptr) { |
| vm_exit_during_initialization("Unable to allocate getCPUIDBrandString_stub"); |
| } |
| CodeBuffer c(cpuid_brand_string_stub_blob); |
| VM_Version_StubGenerator g(&c); |
| getCPUIDBrandString_stub = CAST_TO_FN_PTR(getCPUIDBrandString_stub_t, |
| g.generate_getCPUIDBrandString()); |
| } |
| |
| const char* VM_Version::cpu_model_description(void) { |
| uint32_t cpu_family = extended_cpu_family(); |
| uint32_t cpu_model = extended_cpu_model(); |
| const char* model = nullptr; |
| |
| if (cpu_family == CPU_FAMILY_PENTIUMPRO) { |
| for (uint32_t i = 0; i <= cpu_model; i++) { |
| model = _model_id_pentium_pro[i]; |
| if (model == nullptr) { |
| break; |
| } |
| } |
| } |
| return model; |
| } |
| |
| const char* VM_Version::cpu_brand_string(void) { |
| if (_cpu_brand_string == nullptr) { |
| _cpu_brand_string = NEW_C_HEAP_ARRAY_RETURN_NULL(char, CPU_EBS_MAX_LENGTH, mtInternal); |
| if (nullptr == _cpu_brand_string) { |
| return nullptr; |
| } |
| int ret_val = cpu_extended_brand_string(_cpu_brand_string, CPU_EBS_MAX_LENGTH); |
| if (ret_val != OS_OK) { |
| FREE_C_HEAP_ARRAY(char, _cpu_brand_string); |
| _cpu_brand_string = nullptr; |
| } |
| } |
| return _cpu_brand_string; |
| } |
| |
| const char* VM_Version::cpu_brand(void) { |
| const char* brand = nullptr; |
| |
| if ((_cpuid_info.std_cpuid1_ebx.value & 0xFF) > 0) { |
| int brand_num = _cpuid_info.std_cpuid1_ebx.value & 0xFF; |
| brand = _brand_id[0]; |
| for (int i = 0; brand != nullptr && i <= brand_num; i += 1) { |
| brand = _brand_id[i]; |
| } |
| } |
| return brand; |
| } |
| |
| bool VM_Version::cpu_is_em64t(void) { |
| return ((_cpuid_info.ext_cpuid1_edx.value & INTEL64_FLAG) == INTEL64_FLAG); |
| } |
| |
| bool VM_Version::is_netburst(void) { |
| return (is_intel() && (extended_cpu_family() == CPU_FAMILY_PENTIUM_4)); |
| } |
| |
| bool VM_Version::supports_tscinv_ext(void) { |
| if (!supports_tscinv_bit()) { |
| return false; |
| } |
| |
| if (is_intel()) { |
| return true; |
| } |
| |
| if (is_amd()) { |
| return !is_amd_Barcelona(); |
| } |
| |
| if (is_hygon()) { |
| return true; |
| } |
| |
| return false; |
| } |
| |
| void VM_Version::resolve_cpu_information_details(void) { |
| |
| // in future we want to base this information on proper cpu |
| // and cache topology enumeration such as: |
| // Intel 64 Architecture Processor Topology Enumeration |
| // which supports system cpu and cache topology enumeration |
| // either using 2xAPICIDs or initial APICIDs |
| |
| // currently only rough cpu information estimates |
| // which will not necessarily reflect the exact configuration of the system |
| |
| // this is the number of logical hardware threads |
| // visible to the operating system |
| _no_of_threads = os::processor_count(); |
| |
| // find out number of threads per cpu package |
| int threads_per_package = threads_per_core() * cores_per_cpu(); |
| |
| // use amount of threads visible to the process in order to guess number of sockets |
| _no_of_sockets = _no_of_threads / threads_per_package; |
| |
| // process might only see a subset of the total number of threads |
| // from a single processor package. Virtualization/resource management for example. |
| // If so then just write a hard 1 as num of pkgs. |
| if (0 == _no_of_sockets) { |
| _no_of_sockets = 1; |
| } |
| |
| // estimate the number of cores |
| _no_of_cores = cores_per_cpu() * _no_of_sockets; |
| } |
| |
| |
| const char* VM_Version::cpu_family_description(void) { |
| int cpu_family_id = extended_cpu_family(); |
| if (is_amd()) { |
| if (cpu_family_id < ExtendedFamilyIdLength_AMD) { |
| return _family_id_amd[cpu_family_id]; |
| } |
| } |
| if (is_intel()) { |
| if (cpu_family_id == CPU_FAMILY_PENTIUMPRO) { |
| return cpu_model_description(); |
| } |
| if (cpu_family_id < ExtendedFamilyIdLength_INTEL) { |
| return _family_id_intel[cpu_family_id]; |
| } |
| } |
| if (is_hygon()) { |
| return "Dhyana"; |
| } |
| return "Unknown x86"; |
| } |
| |
| int VM_Version::cpu_type_description(char* const buf, size_t buf_len) { |
| assert(buf != nullptr, "buffer is null!"); |
| assert(buf_len >= CPU_TYPE_DESC_BUF_SIZE, "buffer len should at least be == CPU_TYPE_DESC_BUF_SIZE!"); |
| |
| const char* cpu_type = nullptr; |
| const char* x64 = nullptr; |
| |
| if (is_intel()) { |
| cpu_type = "Intel"; |
| x64 = cpu_is_em64t() ? " Intel64" : ""; |
| } else if (is_amd()) { |
| cpu_type = "AMD"; |
| x64 = cpu_is_em64t() ? " AMD64" : ""; |
| } else if (is_hygon()) { |
| cpu_type = "Hygon"; |
| x64 = cpu_is_em64t() ? " AMD64" : ""; |
| } else { |
| cpu_type = "Unknown x86"; |
| x64 = cpu_is_em64t() ? " x86_64" : ""; |
| } |
| |
| jio_snprintf(buf, buf_len, "%s %s%s SSE SSE2%s%s%s%s%s%s%s%s", |
| cpu_type, |
| cpu_family_description(), |
| supports_ht() ? " (HT)" : "", |
| supports_sse3() ? " SSE3" : "", |
| supports_ssse3() ? " SSSE3" : "", |
| supports_sse4_1() ? " SSE4.1" : "", |
| supports_sse4_2() ? " SSE4.2" : "", |
| supports_sse4a() ? " SSE4A" : "", |
| is_netburst() ? " Netburst" : "", |
| is_intel_family_core() ? " Core" : "", |
| x64); |
| |
| return OS_OK; |
| } |
| |
| int VM_Version::cpu_extended_brand_string(char* const buf, size_t buf_len) { |
| assert(buf != nullptr, "buffer is null!"); |
| assert(buf_len >= CPU_EBS_MAX_LENGTH, "buffer len should at least be == CPU_EBS_MAX_LENGTH!"); |
| assert(getCPUIDBrandString_stub != nullptr, "not initialized"); |
| |
| // invoke newly generated asm code to fetch CPU Brand String |
| getCPUIDBrandString_stub(&_cpuid_info); |
| |
| // fetch results into buffer |
| *((uint32_t*) &buf[0]) = _cpuid_info.proc_name_0; |
| *((uint32_t*) &buf[4]) = _cpuid_info.proc_name_1; |
| *((uint32_t*) &buf[8]) = _cpuid_info.proc_name_2; |
| *((uint32_t*) &buf[12]) = _cpuid_info.proc_name_3; |
| *((uint32_t*) &buf[16]) = _cpuid_info.proc_name_4; |
| *((uint32_t*) &buf[20]) = _cpuid_info.proc_name_5; |
| *((uint32_t*) &buf[24]) = _cpuid_info.proc_name_6; |
| *((uint32_t*) &buf[28]) = _cpuid_info.proc_name_7; |
| *((uint32_t*) &buf[32]) = _cpuid_info.proc_name_8; |
| *((uint32_t*) &buf[36]) = _cpuid_info.proc_name_9; |
| *((uint32_t*) &buf[40]) = _cpuid_info.proc_name_10; |
| *((uint32_t*) &buf[44]) = _cpuid_info.proc_name_11; |
| |
| return OS_OK; |
| } |
| |
| size_t VM_Version::cpu_write_support_string(char* const buf, size_t buf_len) { |
| guarantee(buf != nullptr, "buffer is null!"); |
| guarantee(buf_len > 0, "buffer len not enough!"); |
| |
| unsigned int flag = 0; |
| unsigned int fi = 0; |
| size_t written = 0; |
| const char* prefix = ""; |
| |
| #define WRITE_TO_BUF(string) \ |
| { \ |
| int res = jio_snprintf(&buf[written], buf_len - written, "%s%s", prefix, string); \ |
| if (res < 0) { \ |
| return buf_len - 1; \ |
| } \ |
| written += res; \ |
| if (prefix[0] == '\0') { \ |
| prefix = ", "; \ |
| } \ |
| } |
| |
| for (flag = 1, fi = 0; flag <= 0x20000000 ; flag <<= 1, fi++) { |
| if (flag == HTT_FLAG && (((_cpuid_info.std_cpuid1_ebx.value >> 16) & 0xff) <= 1)) { |
| continue; /* no hyperthreading */ |
| } else if (flag == SEP_FLAG && (cpu_family() == CPU_FAMILY_PENTIUMPRO && ((_cpuid_info.std_cpuid1_eax.value & 0xff) < 0x33))) { |
| continue; /* no fast system call */ |
| } |
| if ((_cpuid_info.std_cpuid1_edx.value & flag) && strlen(_feature_edx_id[fi]) > 0) { |
| WRITE_TO_BUF(_feature_edx_id[fi]); |
| } |
| } |
| |
| for (flag = 1, fi = 0; flag <= 0x20000000; flag <<= 1, fi++) { |
| if ((_cpuid_info.std_cpuid1_ecx.value & flag) && strlen(_feature_ecx_id[fi]) > 0) { |
| WRITE_TO_BUF(_feature_ecx_id[fi]); |
| } |
| } |
| |
| for (flag = 1, fi = 0; flag <= 0x20000000 ; flag <<= 1, fi++) { |
| if ((_cpuid_info.ext_cpuid1_ecx.value & flag) && strlen(_feature_extended_ecx_id[fi]) > 0) { |
| WRITE_TO_BUF(_feature_extended_ecx_id[fi]); |
| } |
| } |
| |
| for (flag = 1, fi = 0; flag <= 0x20000000; flag <<= 1, fi++) { |
| if ((_cpuid_info.ext_cpuid1_edx.value & flag) && strlen(_feature_extended_edx_id[fi]) > 0) { |
| WRITE_TO_BUF(_feature_extended_edx_id[fi]); |
| } |
| } |
| |
| if (supports_tscinv_bit()) { |
| WRITE_TO_BUF("Invariant TSC"); |
| } |
| |
| return written; |
| } |
| |
| /** |
| * Write a detailed description of the cpu to a given buffer, including |
| * feature set. |
| */ |
| int VM_Version::cpu_detailed_description(char* const buf, size_t buf_len) { |
| assert(buf != nullptr, "buffer is null!"); |
| assert(buf_len >= CPU_DETAILED_DESC_BUF_SIZE, "buffer len should at least be == CPU_DETAILED_DESC_BUF_SIZE!"); |
| |
| static const char* unknown = "<unknown>"; |
| char vendor_id[VENDOR_LENGTH]; |
| const char* family = nullptr; |
| const char* model = nullptr; |
| const char* brand = nullptr; |
| int outputLen = 0; |
| |
| family = cpu_family_description(); |
| if (family == nullptr) { |
| family = unknown; |
| } |
| |
| model = cpu_model_description(); |
| if (model == nullptr) { |
| model = unknown; |
| } |
| |
| brand = cpu_brand_string(); |
| |
| if (brand == nullptr) { |
| brand = cpu_brand(); |
| if (brand == nullptr) { |
| brand = unknown; |
| } |
| } |
| |
| *((uint32_t*) &vendor_id[0]) = _cpuid_info.std_vendor_name_0; |
| *((uint32_t*) &vendor_id[4]) = _cpuid_info.std_vendor_name_2; |
| *((uint32_t*) &vendor_id[8]) = _cpuid_info.std_vendor_name_1; |
| vendor_id[VENDOR_LENGTH-1] = '\0'; |
| |
| outputLen = jio_snprintf(buf, buf_len, "Brand: %s, Vendor: %s\n" |
| "Family: %s (0x%x), Model: %s (0x%x), Stepping: 0x%x\n" |
| "Ext. family: 0x%x, Ext. model: 0x%x, Type: 0x%x, Signature: 0x%8.8x\n" |
| "Features: ebx: 0x%8.8x, ecx: 0x%8.8x, edx: 0x%8.8x\n" |
| "Ext. features: eax: 0x%8.8x, ebx: 0x%8.8x, ecx: 0x%8.8x, edx: 0x%8.8x\n" |
| "Supports: ", |
| brand, |
| vendor_id, |
| family, |
| extended_cpu_family(), |
| model, |
| extended_cpu_model(), |
| cpu_stepping(), |
| _cpuid_info.std_cpuid1_eax.bits.ext_family, |
| _cpuid_info.std_cpuid1_eax.bits.ext_model, |
| _cpuid_info.std_cpuid1_eax.bits.proc_type, |
| _cpuid_info.std_cpuid1_eax.value, |
| _cpuid_info.std_cpuid1_ebx.value, |
| _cpuid_info.std_cpuid1_ecx.value, |
| _cpuid_info.std_cpuid1_edx.value, |
| _cpuid_info.ext_cpuid1_eax, |
| _cpuid_info.ext_cpuid1_ebx, |
| _cpuid_info.ext_cpuid1_ecx, |
| _cpuid_info.ext_cpuid1_edx); |
| |
| if (outputLen < 0 || (size_t) outputLen >= buf_len - 1) { |
| if (buf_len > 0) { buf[buf_len-1] = '\0'; } |
| return OS_ERR; |
| } |
| |
| cpu_write_support_string(&buf[outputLen], buf_len - outputLen); |
| |
| return OS_OK; |
| } |
| |
| |
| // Fill in Abstract_VM_Version statics |
| void VM_Version::initialize_cpu_information() { |
| assert(_vm_version_initialized, "should have initialized VM_Version long ago"); |
| assert(!_initialized, "shouldn't be initialized yet"); |
| resolve_cpu_information_details(); |
| |
| // initialize cpu_name and cpu_desc |
| cpu_type_description(_cpu_name, CPU_TYPE_DESC_BUF_SIZE); |
| cpu_detailed_description(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE); |
| _initialized = true; |
| } |
| |
| /** |
| * For information about extracting the frequency from the cpu brand string, please see: |
| * |
| * Intel Processor Identification and the CPUID Instruction |
| * Application Note 485 |
| * May 2012 |
| * |
| * The return value is the frequency in Hz. |
| */ |
| int64_t VM_Version::max_qualified_cpu_freq_from_brand_string(void) { |
| const char* const brand_string = cpu_brand_string(); |
| if (brand_string == nullptr) { |
| return 0; |
| } |
| const int64_t MEGA = 1000000; |
| int64_t multiplier = 0; |
| int64_t frequency = 0; |
| uint8_t idx = 0; |
| // The brand string buffer is at most 48 bytes. |
| // -2 is to prevent buffer overrun when looking for y in yHz, as z is +2 from y. |
| for (; idx < 48-2; ++idx) { |
| // Format is either "x.xxyHz" or "xxxxyHz", where y=M, G, T and x are digits. |
| // Search brand string for "yHz" where y is M, G, or T. |
| if (brand_string[idx+1] == 'H' && brand_string[idx+2] == 'z') { |
| if (brand_string[idx] == 'M') { |
| multiplier = MEGA; |
| } else if (brand_string[idx] == 'G') { |
| multiplier = MEGA * 1000; |
| } else if (brand_string[idx] == 'T') { |
| multiplier = MEGA * MEGA; |
| } |
| break; |
| } |
| } |
| if (multiplier > 0) { |
| // Compute frequency (in Hz) from brand string. |
| if (brand_string[idx-3] == '.') { // if format is "x.xx" |
| frequency = (brand_string[idx-4] - '0') * multiplier; |
| frequency += (brand_string[idx-2] - '0') * multiplier / 10; |
| frequency += (brand_string[idx-1] - '0') * multiplier / 100; |
| } else { // format is "xxxx" |
| frequency = (brand_string[idx-4] - '0') * 1000; |
| frequency += (brand_string[idx-3] - '0') * 100; |
| frequency += (brand_string[idx-2] - '0') * 10; |
| frequency += (brand_string[idx-1] - '0'); |
| frequency *= multiplier; |
| } |
| } |
| return frequency; |
| } |
| |
| |
| int64_t VM_Version::maximum_qualified_cpu_frequency(void) { |
| if (_max_qualified_cpu_frequency == 0) { |
| _max_qualified_cpu_frequency = max_qualified_cpu_freq_from_brand_string(); |
| } |
| return _max_qualified_cpu_frequency; |
| } |
| |
| VM_Version::VM_Features VM_Version::CpuidInfo::feature_flags() const { |
| VM_Features vm_features; |
| if (std_cpuid1_edx.bits.cmpxchg8 != 0) |
| vm_features.set_feature(CPU_CX8); |
| if (std_cpuid1_edx.bits.cmov != 0) |
| vm_features.set_feature(CPU_CMOV); |
| if (std_cpuid1_edx.bits.clflush != 0) |
| 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 (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)) |
| vm_features.set_feature(CPU_FXSR); |
| // HT flag is set for multi-core processors also. |
| if (threads_per_core() > 1) |
| vm_features.set_feature(CPU_HT); |
| if (std_cpuid1_edx.bits.mmx != 0 || (is_amd_family() && |
| ext_cpuid1_edx.bits.mmx != 0)) |
| vm_features.set_feature(CPU_MMX); |
| if (std_cpuid1_edx.bits.sse != 0) |
| vm_features.set_feature(CPU_SSE); |
| if (std_cpuid1_edx.bits.sse2 != 0) |
| vm_features.set_feature(CPU_SSE2); |
| if (std_cpuid1_ecx.bits.sse3 != 0) |
| vm_features.set_feature(CPU_SSE3); |
| if (std_cpuid1_ecx.bits.ssse3 != 0) |
| vm_features.set_feature(CPU_SSSE3); |
| if (std_cpuid1_ecx.bits.sse4_1 != 0) |
| vm_features.set_feature(CPU_SSE4_1); |
| if (std_cpuid1_ecx.bits.sse4_2 != 0) |
| vm_features.set_feature(CPU_SSE4_2); |
| if (std_cpuid1_ecx.bits.popcnt != 0) |
| vm_features.set_feature(CPU_POPCNT); |
| if (sefsl1_cpuid7_edx.bits.apx_f != 0 && |
| xem_xcr0_eax.bits.apx_f != 0 && |
| std_cpuid29_ebx.bits.apx_nci_ndd_nf != 0) { |
| 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) { |
| vm_features.set_feature(CPU_AVX); |
| vm_features.set_feature(CPU_VZEROUPPER); |
| if (sefsl1_cpuid7_eax.bits.sha512 != 0) |
| vm_features.set_feature(CPU_SHA512); |
| if (std_cpuid1_ecx.bits.f16c != 0) |
| vm_features.set_feature(CPU_F16C); |
| if (sef_cpuid7_ebx.bits.avx2 != 0) { |
| vm_features.set_feature(CPU_AVX2); |
| if (sefsl1_cpuid7_eax.bits.avx_ifma != 0) |
| vm_features.set_feature(CPU_AVX_IFMA); |
| } |
| if (sef_cpuid7_ecx.bits.gfni != 0) |
| 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) { |
| vm_features.set_feature(CPU_AVX512F); |
| if (sef_cpuid7_ebx.bits.avx512cd != 0) |
| vm_features.set_feature(CPU_AVX512CD); |
| if (sef_cpuid7_ebx.bits.avx512dq != 0) |
| vm_features.set_feature(CPU_AVX512DQ); |
| if (sef_cpuid7_ebx.bits.avx512ifma != 0) |
| vm_features.set_feature(CPU_AVX512_IFMA); |
| if (sef_cpuid7_ebx.bits.avx512pf != 0) |
| vm_features.set_feature(CPU_AVX512PF); |
| if (sef_cpuid7_ebx.bits.avx512er != 0) |
| vm_features.set_feature(CPU_AVX512ER); |
| if (sef_cpuid7_ebx.bits.avx512bw != 0) |
| vm_features.set_feature(CPU_AVX512BW); |
| if (sef_cpuid7_ebx.bits.avx512vl != 0) |
| vm_features.set_feature(CPU_AVX512VL); |
| if (sef_cpuid7_ecx.bits.avx512_vpopcntdq != 0) |
| vm_features.set_feature(CPU_AVX512_VPOPCNTDQ); |
| if (sef_cpuid7_ecx.bits.avx512_vpclmulqdq != 0) |
| vm_features.set_feature(CPU_AVX512_VPCLMULQDQ); |
| if (sef_cpuid7_ecx.bits.vaes != 0) |
| vm_features.set_feature(CPU_AVX512_VAES); |
| if (sef_cpuid7_ecx.bits.avx512_vnni != 0) |
| vm_features.set_feature(CPU_AVX512_VNNI); |
| if (sef_cpuid7_ecx.bits.avx512_bitalg != 0) |
| vm_features.set_feature(CPU_AVX512_BITALG); |
| if (sef_cpuid7_ecx.bits.avx512_vbmi != 0) |
| vm_features.set_feature(CPU_AVX512_VBMI); |
| if (sef_cpuid7_ecx.bits.avx512_vbmi2 != 0) |
| 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) |
| vm_features.set_feature(CPU_HV); |
| if (sef_cpuid7_ebx.bits.bmi1 != 0) |
| vm_features.set_feature(CPU_BMI1); |
| if (std_cpuid1_edx.bits.tsc != 0) |
| vm_features.set_feature(CPU_TSC); |
| if (ext_cpuid7_edx.bits.tsc_invariance != 0) |
| vm_features.set_feature(CPU_TSCINV_BIT); |
| if (std_cpuid1_ecx.bits.aes != 0) |
| vm_features.set_feature(CPU_AES); |
| if (ext_cpuid1_ecx.bits.lzcnt != 0) |
| vm_features.set_feature(CPU_LZCNT); |
| if (ext_cpuid1_ecx.bits.prefetchw != 0) |
| vm_features.set_feature(CPU_3DNOW_PREFETCH); |
| if (sef_cpuid7_ebx.bits.erms != 0) |
| vm_features.set_feature(CPU_ERMS); |
| if (sef_cpuid7_edx.bits.fast_short_rep_mov != 0) |
| vm_features.set_feature(CPU_FSRM); |
| if (std_cpuid1_ecx.bits.clmul != 0) |
| vm_features.set_feature(CPU_CLMUL); |
| if (sef_cpuid7_ebx.bits.rtm != 0) |
| vm_features.set_feature(CPU_RTM); |
| if (sef_cpuid7_ebx.bits.adx != 0) |
| vm_features.set_feature(CPU_ADX); |
| if (sef_cpuid7_ebx.bits.bmi2 != 0) |
| vm_features.set_feature(CPU_BMI2); |
| if (sef_cpuid7_ebx.bits.sha != 0) |
| vm_features.set_feature(CPU_SHA); |
| if (std_cpuid1_ecx.bits.fma != 0) |
| vm_features.set_feature(CPU_FMA); |
| if (sef_cpuid7_ebx.bits.clflushopt != 0) |
| vm_features.set_feature(CPU_FLUSHOPT); |
| if (sef_cpuid7_ebx.bits.clwb != 0) |
| vm_features.set_feature(CPU_CLWB); |
| if (ext_cpuid1_edx.bits.rdtscp != 0) |
| vm_features.set_feature(CPU_RDTSCP); |
| if (sef_cpuid7_ecx.bits.rdpid != 0) |
| 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)) |
| vm_features.set_feature(CPU_3DNOW_PREFETCH); |
| if (ext_cpuid1_ecx.bits.sse4a != 0) |
| vm_features.set_feature(CPU_SSE4A); |
| } |
| |
| // Intel additional features. |
| if (is_intel()) { |
| if (sef_cpuid7_edx.bits.serialize != 0) |
| vm_features.set_feature(CPU_SERIALIZE); |
| if (_cpuid_info.sef_cpuid7_edx.bits.avx512_fp16 != 0) |
| 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(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) { |
| vm_features.set_feature(CPU_PKU); |
| } |
| if (sef_cpuid7_ecx.bits.ospke != 0) { |
| vm_features.set_feature(CPU_OSPKE); |
| } |
| |
| // Control flow enforcement (CET) features. |
| if (sef_cpuid7_ecx.bits.cet_ss != 0) { |
| vm_features.set_feature(CPU_CET_SS); |
| } |
| if (sef_cpuid7_edx.bits.cet_ibt != 0) { |
| 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())) { |
| vm_features.set_feature(CPU_TSCINV); |
| } |
| return vm_features; |
| } |
| |
| bool VM_Version::os_supports_avx_vectors() { |
| bool retVal = false; |
| int nreg = 4; |
| if (supports_evex()) { |
| // Verify that OS save/restore all bits of EVEX registers |
| // during signal processing. |
| retVal = true; |
| for (int i = 0; i < 16 * nreg; i++) { // 64 bytes per zmm register |
| if (_cpuid_info.zmm_save[i] != ymm_test_value()) { |
| retVal = false; |
| break; |
| } |
| } |
| } else if (supports_avx()) { |
| // Verify that OS save/restore all bits of AVX registers |
| // during signal processing. |
| retVal = true; |
| for (int i = 0; i < 8 * nreg; i++) { // 32 bytes per ymm register |
| if (_cpuid_info.ymm_save[i] != ymm_test_value()) { |
| retVal = false; |
| break; |
| } |
| } |
| // zmm_save will be set on a EVEX enabled machine even if we choose AVX code gen |
| if (retVal == false) { |
| // Verify that OS save/restore all bits of EVEX registers |
| // during signal processing. |
| retVal = true; |
| for (int i = 0; i < 16 * nreg; i++) { // 64 bytes per zmm register |
| if (_cpuid_info.zmm_save[i] != ymm_test_value()) { |
| retVal = false; |
| break; |
| } |
| } |
| } |
| } |
| return retVal; |
| } |
| |
| bool VM_Version::os_supports_apx_egprs() { |
| if (!supports_apx_f()) { |
| return false; |
| } |
| if (_cpuid_info.apx_save[0] != egpr_test_value() || |
| _cpuid_info.apx_save[1] != egpr_test_value()) { |
| return false; |
| } |
| return true; |
| } |
| |
| uint VM_Version::cores_per_cpu() { |
| uint result = 1; |
| if (is_intel()) { |
| bool supports_topology = supports_processor_topology(); |
| if (supports_topology) { |
| result = _cpuid_info.tpl_cpuidB1_ebx.bits.logical_cpus / |
| _cpuid_info.tpl_cpuidB0_ebx.bits.logical_cpus; |
| } |
| if (!supports_topology || result == 0) { |
| result = (_cpuid_info.dcp_cpuid4_eax.bits.cores_per_cpu + 1); |
| } |
| } else if (is_amd_family()) { |
| result = (_cpuid_info.ext_cpuid8_ecx.bits.cores_per_cpu + 1); |
| } else if (is_zx()) { |
| bool supports_topology = supports_processor_topology(); |
| if (supports_topology) { |
| result = _cpuid_info.tpl_cpuidB1_ebx.bits.logical_cpus / |
| _cpuid_info.tpl_cpuidB0_ebx.bits.logical_cpus; |
| } |
| if (!supports_topology || result == 0) { |
| result = (_cpuid_info.dcp_cpuid4_eax.bits.cores_per_cpu + 1); |
| } |
| } |
| return result; |
| } |
| |
| uint VM_Version::threads_per_core() { |
| uint result = 1; |
| if (is_intel() && supports_processor_topology()) { |
| result = _cpuid_info.tpl_cpuidB0_ebx.bits.logical_cpus; |
| } else if (is_zx() && supports_processor_topology()) { |
| result = _cpuid_info.tpl_cpuidB0_ebx.bits.logical_cpus; |
| } else if (_cpuid_info.std_cpuid1_edx.bits.ht != 0) { |
| if (cpu_family() >= 0x17) { |
| result = _cpuid_info.ext_cpuid1E_ebx.bits.threads_per_core + 1; |
| } else { |
| result = _cpuid_info.std_cpuid1_ebx.bits.threads_per_cpu / |
| cores_per_cpu(); |
| } |
| } |
| return (result == 0 ? 1 : result); |
| } |
| |
| uint VM_Version::L1_line_size() { |
| uint result = 0; |
| if (is_intel()) { |
| result = (_cpuid_info.dcp_cpuid4_ebx.bits.L1_line_size + 1); |
| } else if (is_amd_family()) { |
| result = _cpuid_info.ext_cpuid5_ecx.bits.L1_line_size; |
| } else if (is_zx()) { |
| result = (_cpuid_info.dcp_cpuid4_ebx.bits.L1_line_size + 1); |
| } |
| if (result < 32) // not defined ? |
| result = 32; // 32 bytes by default on x86 and other x64 |
| return result; |
| } |
| |
| bool VM_Version::is_intel_tsc_synched_at_init() { |
| if (is_intel_family_core()) { |
| uint32_t ext_model = extended_cpu_model(); |
| if (ext_model == CPU_MODEL_NEHALEM_EP || |
| ext_model == CPU_MODEL_WESTMERE_EP || |
| ext_model == CPU_MODEL_SANDYBRIDGE_EP || |
| ext_model == CPU_MODEL_IVYBRIDGE_EP) { |
| // <= 2-socket invariant tsc support. EX versions are usually used |
| // in > 2-socket systems and likely don't synchronize tscs at |
| // initialization. |
| // Code that uses tsc values must be prepared for them to arbitrarily |
| // jump forward or backward. |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| int VM_Version::allocate_prefetch_distance(bool use_watermark_prefetch) { |
| // Hardware prefetching (distance/size in bytes): |
| // Pentium 3 - 64 / 32 |
| // Pentium 4 - 256 / 128 |
| // Athlon - 64 / 32 ???? |
| // Opteron - 128 / 64 only when 2 sequential cache lines accessed |
| // Core - 128 / 64 |
| // |
| // Software prefetching (distance in bytes / instruction with best score): |
| // Pentium 3 - 128 / prefetchnta |
| // Pentium 4 - 512 / prefetchnta |
| // Athlon - 128 / prefetchnta |
| // Opteron - 256 / prefetchnta |
| // Core - 256 / prefetchnta |
| // It will be used only when AllocatePrefetchStyle > 0 |
| |
| if (is_amd_family()) { // AMD | Hygon |
| if (supports_sse2()) { |
| return 256; // Opteron |
| } else { |
| return 128; // Athlon |
| } |
| } else { // Intel |
| if (supports_sse3() && is_intel_server_family()) { |
| if (supports_sse4_2() && supports_ht()) { // Nehalem based cpus |
| return 192; |
| } else if (use_watermark_prefetch) { // watermark prefetching on Core |
| return 384; |
| } |
| } |
| if (supports_sse2()) { |
| if (is_intel_server_family()) { |
| return 256; // Pentium M, Core, Core2 |
| } else { |
| return 512; // Pentium 4 |
| } |
| } else { |
| return 128; // Pentium 3 (and all other old CPUs) |
| } |
| } |
| } |
| |
| bool VM_Version::is_intrinsic_supported(vmIntrinsicID id) { |
| assert(id != vmIntrinsics::_none, "must be a VM intrinsic"); |
| switch (id) { |
| case vmIntrinsics::_floatToFloat16: |
| case vmIntrinsics::_float16ToFloat: |
| if (!supports_float16()) { |
| return false; |
| } |
| break; |
| default: |
| break; |
| } |
| 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; |
| } |
| } |
| } |