From 133c0424b9df25ec8fb95404ee64e611ebad31e2 Mon Sep 17 00:00:00 2001 From: Ashutosh Mehra Date: Mon, 6 Apr 2026 15:30:55 +0000 Subject: [PATCH] 8364584: Inconsistency in setting up cpu feature bits Reviewed-by: kvn, iklam --- .../cpu/aarch64/vm_version_aarch64.cpp | 113 ++++++------- .../cpu/aarch64/vm_version_aarch64.hpp | 2 + .../cpu/x86/stubGenerator_x86_64_aes.cpp | 2 +- .../cpu/x86/stubGenerator_x86_64_fmod.cpp | 2 +- src/hotspot/cpu/x86/vm_version_x86.cpp | 153 ++++++++---------- src/hotspot/cpu/x86/vm_version_x86.hpp | 5 + .../share/runtime/abstract_vm_version.hpp | 15 ++ .../cpuflags/CPUFeaturesClearTest.java | 143 ++++++++++++++++ 8 files changed, 286 insertions(+), 149 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/cpuflags/CPUFeaturesClearTest.java diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp index 8ccffac25a8..b39d1618b3d 100644 --- a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp @@ -97,8 +97,9 @@ void VM_Version::initialize() { _supports_atomic_getadd8 = true; get_os_cpu_info(); + _cpu_features = _features; - int dcache_line = VM_Version::dcache_line_size(); + int dcache_line = dcache_line_size(); // Limit AllocatePrefetchDistance so that it does not exceed the // static constraint of 512 defined in runtime/globals.hpp. @@ -146,7 +147,7 @@ void VM_Version::initialize() { // if dcpop is available publish data cache line flush size via // generic field, otherwise let if default to zero thereby // disabling writeback - if (VM_Version::supports_dcpop()) { + if (supports_dcpop()) { _data_cache_line_flush_size = dcache_line; } } @@ -267,14 +268,24 @@ void VM_Version::initialize() { } } - if (FLAG_IS_DEFAULT(UseCRC32)) { - UseCRC32 = VM_Version::supports_crc32(); + if (supports_sha1() || supports_sha256() || + supports_sha3() || supports_sha512()) { + if (FLAG_IS_DEFAULT(UseSHA)) { + FLAG_SET_DEFAULT(UseSHA, true); + } else if (!UseSHA) { + clear_feature(CPU_SHA1); + clear_feature(CPU_SHA2); + clear_feature(CPU_SHA3); + clear_feature(CPU_SHA512); + } + } else if (UseSHA) { + warning("SHA instructions are not available on this CPU"); + FLAG_SET_DEFAULT(UseSHA, false); } - if (UseCRC32 && !VM_Version::supports_crc32()) { - warning("UseCRC32 specified, but not supported on this CPU"); - FLAG_SET_DEFAULT(UseCRC32, false); - } + CHECK_CPU_FEATURE(supports_crc32, CRC32); + CHECK_CPU_FEATURE(supports_lse, LSE); + CHECK_CPU_FEATURE(supports_aes, AES); if (_cpu == CPU_ARM && model_is_in({ CPU_MODEL_ARM_NEOVERSE_V1, CPU_MODEL_ARM_NEOVERSE_V2, @@ -287,7 +298,7 @@ void VM_Version::initialize() { } } - if (UseCryptoPmullForCRC32 && (!VM_Version::supports_pmull() || !VM_Version::supports_sha3() || !VM_Version::supports_crc32())) { + if (UseCryptoPmullForCRC32 && (!supports_pmull() || !supports_sha3() || !supports_crc32())) { warning("UseCryptoPmullForCRC32 specified, but not supported on this CPU"); FLAG_SET_DEFAULT(UseCryptoPmullForCRC32, false); } @@ -301,48 +312,40 @@ void VM_Version::initialize() { FLAG_SET_DEFAULT(UseVectorizedMismatchIntrinsic, false); } - if (VM_Version::supports_lse()) { - if (FLAG_IS_DEFAULT(UseLSE)) - FLAG_SET_DEFAULT(UseLSE, true); - } else { - if (UseLSE) { - warning("UseLSE specified, but not supported on this CPU"); - FLAG_SET_DEFAULT(UseLSE, false); - } - } - - if (VM_Version::supports_aes()) { - UseAES = UseAES || FLAG_IS_DEFAULT(UseAES); - UseAESIntrinsics = - UseAESIntrinsics || (UseAES && FLAG_IS_DEFAULT(UseAESIntrinsics)); - if (UseAESIntrinsics && !UseAES) { - warning("UseAESIntrinsics enabled, but UseAES not, enabling"); - UseAES = true; + if (supports_aes()) { + if (FLAG_IS_DEFAULT(UseAESIntrinsics)) { + FLAG_SET_DEFAULT(UseAESIntrinsics, true); } if (FLAG_IS_DEFAULT(UseAESCTRIntrinsics)) { FLAG_SET_DEFAULT(UseAESCTRIntrinsics, true); } } else { - if (UseAES) { - warning("AES instructions are not available on this CPU"); - FLAG_SET_DEFAULT(UseAES, false); - } - if (UseAESIntrinsics) { - warning("AES intrinsics are not available on this CPU"); - FLAG_SET_DEFAULT(UseAESIntrinsics, false); - } - if (UseAESCTRIntrinsics) { - warning("AES/CTR intrinsics are not available on this CPU"); - FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false); + if (!UseAES) { + if (UseAESIntrinsics) { + warning("AES intrinsics require UseAES flag to be enabled. Intrinsics will be disabled."); + FLAG_SET_DEFAULT(UseAESIntrinsics, false); + } + if (UseAESCTRIntrinsics) { + warning("AES/CTR intrinsics require UseAES flag to be enabled. Intrinsics will be disabled."); + FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false); + } + } else if (!cpu_supports_aes()) { + if (UseAESIntrinsics) { + warning("AES intrinsics are not available on this CPU"); + FLAG_SET_DEFAULT(UseAESIntrinsics, false); + } + if (UseAESCTRIntrinsics) { + warning("AES/CTR intrinsics are not available on this CPU"); + FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false); + } } } - if (FLAG_IS_DEFAULT(UseCRC32Intrinsics)) { UseCRC32Intrinsics = true; } - if (VM_Version::supports_crc32()) { + if (supports_crc32()) { if (FLAG_IS_DEFAULT(UseCRC32CIntrinsics)) { FLAG_SET_DEFAULT(UseCRC32CIntrinsics, true); } @@ -359,17 +362,7 @@ void VM_Version::initialize() { UseMD5Intrinsics = true; } - if (VM_Version::supports_sha1() || VM_Version::supports_sha256() || - VM_Version::supports_sha3() || VM_Version::supports_sha512()) { - if (FLAG_IS_DEFAULT(UseSHA)) { - FLAG_SET_DEFAULT(UseSHA, true); - } - } else if (UseSHA) { - warning("SHA instructions are not available on this CPU"); - FLAG_SET_DEFAULT(UseSHA, false); - } - - if (UseSHA && VM_Version::supports_sha1()) { + if (UseSHA && supports_sha1()) { if (FLAG_IS_DEFAULT(UseSHA1Intrinsics)) { FLAG_SET_DEFAULT(UseSHA1Intrinsics, true); } @@ -378,7 +371,7 @@ void VM_Version::initialize() { FLAG_SET_DEFAULT(UseSHA1Intrinsics, false); } - if (UseSHA && VM_Version::supports_sha256()) { + if (UseSHA && supports_sha256()) { if (FLAG_IS_DEFAULT(UseSHA256Intrinsics)) { FLAG_SET_DEFAULT(UseSHA256Intrinsics, true); } @@ -388,7 +381,7 @@ void VM_Version::initialize() { } if (UseSHA) { - // No need to check VM_Version::supports_sha3(), since a fallback GPR intrinsic implementation is provided. + // No need to check supports_sha3(), since a fallback GPR intrinsic implementation is provided. if (FLAG_IS_DEFAULT(UseSHA3Intrinsics)) { FLAG_SET_DEFAULT(UseSHA3Intrinsics, true); } @@ -398,7 +391,7 @@ void VM_Version::initialize() { FLAG_SET_DEFAULT(UseSHA3Intrinsics, false); } - if (UseSHA3Intrinsics && VM_Version::supports_sha3()) { + if (UseSHA3Intrinsics && supports_sha3()) { // Auto-enable UseSIMDForSHA3Intrinsic on hardware with performance benefit. // Note that the evaluation of SHA3 extension Intrinsics shows better performance // on Apple and Qualcomm silicon but worse performance on Neoverse V1 and N2. @@ -408,12 +401,12 @@ void VM_Version::initialize() { } } } - if (UseSHA3Intrinsics && UseSIMDForSHA3Intrinsic && !VM_Version::supports_sha3()) { + if (UseSHA3Intrinsics && UseSIMDForSHA3Intrinsic && !supports_sha3()) { 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 (UseSHA && VM_Version::supports_sha512()) { + if (UseSHA && supports_sha512()) { if (FLAG_IS_DEFAULT(UseSHA512Intrinsics)) { FLAG_SET_DEFAULT(UseSHA512Intrinsics, true); } @@ -426,7 +419,7 @@ void VM_Version::initialize() { FLAG_SET_DEFAULT(UseSHA, false); } - if (VM_Version::supports_pmull()) { + if (supports_pmull()) { if (FLAG_IS_DEFAULT(UseGHASHIntrinsics)) { FLAG_SET_DEFAULT(UseGHASHIntrinsics, true); } @@ -477,7 +470,7 @@ void VM_Version::initialize() { FLAG_SET_DEFAULT(UseBlockZeroing, true); } if (FLAG_IS_DEFAULT(BlockZeroingLowLimit)) { - FLAG_SET_DEFAULT(BlockZeroingLowLimit, 4 * VM_Version::zva_length()); + FLAG_SET_DEFAULT(BlockZeroingLowLimit, 4 * zva_length()); } } else if (UseBlockZeroing) { if (!FLAG_IS_DEFAULT(UseBlockZeroing)) { @@ -486,11 +479,11 @@ void VM_Version::initialize() { FLAG_SET_DEFAULT(UseBlockZeroing, false); } - if (VM_Version::supports_sve2()) { + if (supports_sve2()) { if (FLAG_IS_DEFAULT(UseSVE)) { FLAG_SET_DEFAULT(UseSVE, 2); } - } else if (VM_Version::supports_sve()) { + } else if (supports_sve()) { if (FLAG_IS_DEFAULT(UseSVE)) { FLAG_SET_DEFAULT(UseSVE, 1); } else if (UseSVE > 1) { @@ -541,7 +534,7 @@ void VM_Version::initialize() { // 1) this code has been built with branch-protection and // 2) the CPU/OS supports it #ifdef __ARM_FEATURE_PAC_DEFAULT - if (!VM_Version::supports_paca()) { + if (!supports_paca()) { // Disable PAC to prevent illegal instruction crashes. warning("ROP-protection specified, but not supported on this CPU. Disabling ROP-protection."); } else { diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp index 378524fe168..f8274554f1c 100644 --- a/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp @@ -193,6 +193,8 @@ public: return (features & BIT_MASK(flag)) != 0; } + static bool cpu_supports_aes() { return supports_feature(_cpu_features, CPU_AES); } + static int cpu_family() { return _cpu; } static int cpu_model() { return _model; } static int cpu_model2() { return _model2; } diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp index 1fa80c9d967..162c92d5190 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp @@ -220,7 +220,7 @@ void StubGenerator::generate_aes_stubs() { StubRoutines::_cipherBlockChaining_decryptAESCrypt = generate_cipherBlockChaining_decryptAESCrypt_Parallel(); StubRoutines::_electronicCodeBook_encryptAESCrypt = generate_electronicCodeBook_encryptAESCrypt_Parallel(); StubRoutines::_electronicCodeBook_decryptAESCrypt = generate_electronicCodeBook_decryptAESCrypt_Parallel(); - if (VM_Version::supports_avx2()) { + if (VM_Version::supports_avx2() && VM_Version::supports_clmul()) { StubRoutines::_galoisCounterMode_AESCrypt = generate_avx2_galoisCounterMode_AESCrypt(); } } diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_fmod.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_fmod.cpp index b1eaa4b8031..a0962943556 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_fmod.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_fmod.cpp @@ -78,7 +78,7 @@ address StubGenerator::generate_libmFmod() { address start = __ pc(); __ enter(); // required for proper stackwalking of RuntimeStub frame - if (VM_Version::supports_avx512vlbwdq()) { // AVX512 version + if (VM_Version::supports_avx512vlbwdq() && VM_Version::supports_fma()) { // AVX512 version // Source used to generate the AVX512 fmod assembly below: // diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp index fc4cfbc5a8b..7899a2f7e51 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.cpp +++ b/src/hotspot/cpu/x86/vm_version_x86.cpp @@ -1094,15 +1094,35 @@ void VM_Version::get_processor_features() { } } - // 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"); + // Currently APX support is only enabled for targets supporting AVX512VL feature. + if (supports_apx_f() && os_supports_apx_egprs() && supports_avx512vl()) { + if (FLAG_IS_DEFAULT(UseAPX)) { + UseAPX = false; // by default UseAPX is false + } else if (!UseAPX) { + _features.clear_feature(CPU_APX_F); + } + } else if (UseAPX) { + if (!FLAG_IS_DEFAULT(UseAPX)) { + warning("APX is not supported on this CPU, setting it to false)"); + } FLAG_SET_DEFAULT(UseAPX, false); } - if (!UseAPX) { - _features.clear_feature(CPU_APX_F); + CHECK_CPU_FEATURE(supports_clmul, CLMUL); + CHECK_CPU_FEATURE(supports_aes, AES); + CHECK_CPU_FEATURE(supports_fma, FMA); + + if (supports_sha() || (supports_avx2() && supports_bmi2())) { + if (FLAG_IS_DEFAULT(UseSHA)) { + UseSHA = true; + } else if (!UseSHA) { + _features.clear_feature(CPU_SHA); + } + } else if (UseSHA) { + if (!FLAG_IS_DEFAULT(UseSHA)) { + warning("SHA instructions are not available on this CPU"); + } + FLAG_SET_DEFAULT(UseSHA, false); } if (FLAG_IS_DEFAULT(IntelJccErratumMitigation)) { @@ -1152,9 +1172,40 @@ void VM_Version::get_processor_features() { // Use AES instructions if available. if (supports_aes()) { - if (FLAG_IS_DEFAULT(UseAES)) { - FLAG_SET_DEFAULT(UseAES, true); + if (supports_sse3()) { + if (FLAG_IS_DEFAULT(UseAESIntrinsics)) { + FLAG_SET_DEFAULT(UseAESIntrinsics, true); + } + } else if (UseAESIntrinsics) { + // The AES intrinsic stubs require AES instruction support (of course) + // but also require sse3 mode or higher for instructions it use. + if (!FLAG_IS_DEFAULT(UseAESIntrinsics)) { + warning("X86 AES intrinsics require SSE3 instructions or higher. Intrinsics will be disabled."); + } + FLAG_SET_DEFAULT(UseAESIntrinsics, false); } + if (!UseAESIntrinsics) { + if (UseAESCTRIntrinsics) { + if (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 if (UseAESCTRIntrinsics) { + // The AES-CTR intrinsic stubs require AES instruction support (of course) + // but also require sse4.1 mode or higher for instructions it use. + if (!FLAG_IS_DEFAULT(UseAESCTRIntrinsics)) { + warning("X86 AES-CTR intrinsics require SSE4.1 instructions or higher. Intrinsics will be disabled."); + } + FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false); + } + } + } else { if (!UseAES) { if (UseAESIntrinsics && !FLAG_IS_DEFAULT(UseAESIntrinsics)) { warning("AES intrinsics require UseAES flag to be enabled. Intrinsics will be disabled."); @@ -1164,66 +1215,16 @@ void VM_Version::get_processor_features() { warning("AES_CTR intrinsics require UseAES flag to be enabled. AES_CTR intrinsics will be disabled."); } FLAG_SET_DEFAULT(UseAESCTRIntrinsics, 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); + } else if (!cpu_supports_aes()) { + if (UseAESIntrinsics && !FLAG_IS_DEFAULT(UseAESIntrinsics)) { + warning("AES intrinsics are not available on this CPU"); } - - // --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); - } + FLAG_SET_DEFAULT(UseAESIntrinsics, false); + if (UseAESCTRIntrinsics && !FLAG_IS_DEFAULT(UseAESCTRIntrinsics)) { + warning("AES-CTR intrinsics are not available on this CPU"); } - // --AES-CTR ends-- + FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false); } - } 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)) { @@ -1323,32 +1324,10 @@ void VM_Version::get_processor_features() { FLAG_SET_DEFAULT(UseBASE64Intrinsics, false); } - if (supports_fma()) { - if (FLAG_IS_DEFAULT(UseFMA)) { - UseFMA = true; - } - } else if (UseFMA) { - if (!FLAG_IS_DEFAULT(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) { - if (!FLAG_IS_DEFAULT(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); diff --git a/src/hotspot/cpu/x86/vm_version_x86.hpp b/src/hotspot/cpu/x86/vm_version_x86.hpp index 4f3580d216c..f721635a02e 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.hpp +++ b/src/hotspot/cpu/x86/vm_version_x86.hpp @@ -535,6 +535,10 @@ protected: static const char* _features_names[]; + static void clear_feature(Feature_Flag feature) { + _features.clear_feature(feature); + } + static void clear_cpu_features() { _features = VM_Features(); _cpu_features = VM_Features(); @@ -930,6 +934,7 @@ public: // Feature identification not affected by VM flags // static bool cpu_supports_evex() { return _cpu_features.supports_feature(CPU_AVX512F); } + static bool cpu_supports_aes() { return _cpu_features.supports_feature(CPU_AES); } static bool supports_avx512_simd_sort() { if (supports_avx512dq()) { diff --git a/src/hotspot/share/runtime/abstract_vm_version.hpp b/src/hotspot/share/runtime/abstract_vm_version.hpp index 17ade2c068d..61a8aa84080 100644 --- a/src/hotspot/share/runtime/abstract_vm_version.hpp +++ b/src/hotspot/share/runtime/abstract_vm_version.hpp @@ -45,6 +45,21 @@ class outputStream; class stringStream; enum class vmIntrinsicID; +// Helper macro to test and set VM flag and corresponding cpu feature +#define CHECK_CPU_FEATURE(feature_test_fn, feature) \ + if (feature_test_fn()) { \ + if (FLAG_IS_DEFAULT(Use##feature)) { \ + FLAG_SET_DEFAULT(Use##feature, true); \ + } else if (!Use##feature) { \ + clear_feature(CPU_##feature); \ + } \ + } else if (Use##feature) { \ + if (!FLAG_IS_DEFAULT(Use##feature)) { \ + warning(#feature " instructions not available on this CPU"); \ + } \ + FLAG_SET_DEFAULT(Use##feature, false); \ + } + // Abstract_VM_Version provides information about the VM. class Abstract_VM_Version: AllStatic { diff --git a/test/hotspot/jtreg/compiler/cpuflags/CPUFeaturesClearTest.java b/test/hotspot/jtreg/compiler/cpuflags/CPUFeaturesClearTest.java new file mode 100644 index 00000000000..a0fb3525381 --- /dev/null +++ b/test/hotspot/jtreg/compiler/cpuflags/CPUFeaturesClearTest.java @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /test/lib / + * @modules java.base/jdk.internal.misc + * java.management + * @requires os.simpleArch == "x64" | os.simpleArch == "aarch64" + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm/timeout=600 -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -Xbatch + * compiler.cpuflags.CPUFeaturesClearTest + */ + +package compiler.cpuflags; + +import java.util.List; + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.Platform; +import jdk.test.lib.process.ProcessTools; +import jdk.test.whitebox.WhiteBox; +import jdk.test.whitebox.cpuinfo.CPUInfo; +import static jdk.test.lib.cli.CommandLineOptionTest.*; + +public class CPUFeaturesClearTest { + private static List cpuFeaturesList; + public void runTestCases() throws Throwable { + if (Platform.isX64()) { + testX86Flags(); + } else if (Platform.isAArch64()) { + testAArch64Flags(); + } + } + + String[] generateArgs(String vmFlag) { + String[] args = {"-Xlog:os+cpu", "-XX:+UnlockDiagnosticVMOptions", vmFlag, "-version"}; + return args; + } + + public void testX86Flags() throws Throwable { + OutputAnalyzer outputAnalyzer; + String vmFlagsToTest[] = {"UseCLMUL", "UseAES", "UseFMA", "UseSHA"}; + String cpuFeatures[] = {"clmul", "aes", "fma", "sha"}; + for (int i = 0; i < vmFlagsToTest.length; i++) { + String vmFlag = vmFlagsToTest[i]; + String cpuFeature = cpuFeatures[i]; + outputAnalyzer = ProcessTools.executeTestJava(generateArgs(prepareBooleanFlag(vmFlag, false))); + outputAnalyzer.shouldNotMatch("[os,cpu] CPU: .* " + cpuFeatures[i] + ".*"); + } + if (isCpuFeatureSupported("sse4")) { + outputAnalyzer = ProcessTools.executeTestJava(generateArgs(prepareNumericFlag("UseSSE", 3))); + outputAnalyzer.shouldNotMatch("[os,cpu] CPU: .* sse4.*"); + } + if (isCpuFeatureSupported("sse3")) { + outputAnalyzer = ProcessTools.executeTestJava(generateArgs(prepareNumericFlag("UseSSE", 2))); + outputAnalyzer.shouldNotMatch("[os,cpu] CPU: .* sse3.*"); + outputAnalyzer.shouldNotMatch("[os,cpu] CPU: .* ssse3.*"); + } + if (isCpuFeatureSupported("sse2")) { + outputAnalyzer = ProcessTools.executeTestJava(generateArgs(prepareNumericFlag("UseSSE", 1))); + outputAnalyzer.shouldNotMatch("[os,cpu] CPU: .* sse2.*"); + } + if (isCpuFeatureSupported("sse")) { + outputAnalyzer = ProcessTools.executeTestJava(generateArgs(prepareNumericFlag("UseSSE", 0))); + outputAnalyzer.shouldNotMatch("[os,cpu] CPU: .* sse.*"); + } + if (isCpuFeatureSupported("avx512f")) { + outputAnalyzer = ProcessTools.executeTestJava(generateArgs(prepareNumericFlag("UseAVX", 2))); + outputAnalyzer.shouldNotMatch("[os,cpu] CPU: .* avx512.*"); + } + if (isCpuFeatureSupported("avx2")) { + outputAnalyzer = ProcessTools.executeTestJava(generateArgs(prepareNumericFlag("UseAVX", 1))); + outputAnalyzer.shouldNotMatch("[os,cpu] CPU: .* avx2.*"); + } + if (isCpuFeatureSupported("avx")) { + outputAnalyzer = ProcessTools.executeTestJava(generateArgs(prepareNumericFlag("UseAVX", 0))); + outputAnalyzer.shouldNotMatch("[os,cpu] CPU: .* avx.*"); + } + } + + public void testAArch64Flags() throws Throwable { + OutputAnalyzer outputAnalyzer; + String vmFlagsToTest[] = {"UseCRC32", "UseLSE", "UseAES"}; + String cpuFeatures[] = {"crc32", "lse", "aes"}; + for (int i = 0; i < vmFlagsToTest.length; i++) { + String vmFlag = vmFlagsToTest[i]; + String cpuFeature = cpuFeatures[i]; + outputAnalyzer = ProcessTools.executeTestJava(generateArgs(prepareBooleanFlag(vmFlag, false))); + outputAnalyzer.shouldNotMatch("[os,cpu] CPU: .* " + cpuFeatures[i] + ".*"); + } + + // Disabling UseSHA should clear all shaXXX cpu features + outputAnalyzer = ProcessTools.executeTestJava(generateArgs(prepareBooleanFlag("UseSHA", false))); + outputAnalyzer.shouldNotMatch("[os,cpu] CPU: .* sha1.*"); + outputAnalyzer.shouldNotMatch("[os,cpu] CPU: .* sha256.*"); + outputAnalyzer.shouldNotMatch("[os,cpu] CPU: .* sha3.*"); + outputAnalyzer.shouldNotMatch("[os,cpu] CPU: .* sha512.*"); + + if (isCpuFeatureSupported("sve2")) { + outputAnalyzer = ProcessTools.executeTestJava(generateArgs(prepareNumericFlag("UseSVE", 1))); + outputAnalyzer.shouldNotMatch("[os,cpu] CPU: .* sve2.*"); + verifyOutput(null, new String[]{"sve2"}, null, outputAnalyzer); + } + if (isCpuFeatureSupported("sve")) { + outputAnalyzer = ProcessTools.executeTestJava(generateArgs(prepareNumericFlag("UseSVE", 0))); + outputAnalyzer.shouldNotMatch("[os,cpu] CPU: .* sve.*"); + verifyOutput(null, new String[]{"sve"}, null, outputAnalyzer); + } + } + + static boolean isCpuFeatureSupported(String feature) { + return cpuFeaturesList.contains(feature); + } + + public static void main(String args[]) throws Throwable { + cpuFeaturesList = CPUInfo.getFeatures(); + new CPUFeaturesClearTest().runTestCases(); + } +}