Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions src/hotspot/os_cpu/windows_aarch64/sve_helper_windows_aarch64.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
; 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.
;

; int get_sve_vector_length_impl(void);
;
; Returns the current SVE vector length in bytes.
; Uses the RDVL instruction which returns imm * VL in bytes.
; With imm=1 this gives the SVE vector length directly.

ALIGN 4
EXPORT get_sve_vector_length_impl
AREA sve_helper_text, CODE, READONLY

get_sve_vector_length_impl
rdvl x0, 1
ret

END
54 changes: 49 additions & 5 deletions src/hotspot/os_cpu/windows_aarch64/vm_version_windows_aarch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,32 +26,76 @@
#include "runtime/os.hpp"
#include "runtime/vm_version.hpp"

// Since PF_ARM_SVE_INSTRUCTIONS_AVAILABLE and related constants were added in
// Windows 11 (version 24H2) and in Windows Server 2025, we define them here for
// compatibility with older SDK versions.
#ifndef PF_ARM_SVE_INSTRUCTIONS_AVAILABLE
#define PF_ARM_SVE_INSTRUCTIONS_AVAILABLE 46
#endif

#ifndef PF_ARM_SVE2_INSTRUCTIONS_AVAILABLE
#define PF_ARM_SVE2_INSTRUCTIONS_AVAILABLE 47
#endif

#ifndef PF_ARM_SVE_BITPERM_INSTRUCTIONS_AVAILABLE
#define PF_ARM_SVE_BITPERM_INSTRUCTIONS_AVAILABLE 51
#endif

#ifndef PF_ARM_V82_FP16_INSTRUCTIONS_AVAILABLE
#define PF_ARM_V82_FP16_INSTRUCTIONS_AVAILABLE 67
#endif

// Assembly helper implemented in sve_helper_windows_aarch64.S. Executes the
// RDVL instruction to return the vector length in bytes.
extern "C" int get_sve_vector_length_impl(void);

int VM_Version::get_current_sve_vector_length() {
assert(VM_Version::supports_sve(), "should not call this");
ShouldNotReachHere();
return 0;
return get_sve_vector_length_impl();
}

int VM_Version::set_and_get_current_sve_vector_length(int length) {
assert(VM_Version::supports_sve(), "should not call this");
ShouldNotReachHere();
return 0;

// Unlike Linux, Windows does not present a way to modify the VL (the
// rationale is that the OS expects the application to use the maximum vector
// length supported by the hardware), so we simply return the current VL. The
// caller (`VM_Version::initialize()`) will print a warning and move on.
return get_sve_vector_length_impl();
}

void VM_Version::get_os_cpu_info() {

if (IsProcessorFeaturePresent(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE)) {
set_feature(CPU_CRC32);
}

if (IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE)) {
set_feature(CPU_AES);
set_feature(CPU_SHA1);
set_feature(CPU_SHA2);
}

if (IsProcessorFeaturePresent(PF_ARM_VFP_32_REGISTERS_AVAILABLE)) {
set_feature(CPU_ASIMD);
}
// No check for CPU_PMULL, CPU_SVE, CPU_SVE2

if (IsProcessorFeaturePresent(PF_ARM_SVE_INSTRUCTIONS_AVAILABLE)) {
set_feature(CPU_SVE);
}

if (IsProcessorFeaturePresent(PF_ARM_SVE2_INSTRUCTIONS_AVAILABLE)) {
set_feature(CPU_SVE2);
}

if (IsProcessorFeaturePresent(PF_ARM_SVE_BITPERM_INSTRUCTIONS_AVAILABLE)) {
set_feature(CPU_SVEBITPERM);
}

if (IsProcessorFeaturePresent(PF_ARM_V82_FP16_INSTRUCTIONS_AVAILABLE)) {
set_feature(CPU_FPHP);
set_feature(CPU_ASIMDHP);
}

__int64 dczid_el0 = _ReadStatusReg(0x5807 /* ARM64_DCZID_EL0 */);

Expand Down
189 changes: 189 additions & 0 deletions test/hotspot/jtreg/compiler/c2/aarch64/TestSVEFeatureDetection.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
/*
* Copyright (c) 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.
*/

/*
* @test
* @summary Verify SVE/SVE2 feature detection for both Windows and Linux.
*
* @requires os.arch == "aarch64" & vm.compiler2.enabled
* @library /test/lib /
* @build jdk.test.whitebox.WhiteBox
* @run driver jdk.test.lib.helpers.ClassFileInstaller
* jdk.test.whitebox.WhiteBox
*
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
* -XX:+WhiteBoxAPI compiler.c2.aarch64.TestSVEFeatureDetection
*/

package compiler.c2.aarch64;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import jdk.test.lib.Asserts;
import jdk.test.lib.process.ProcessTools;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.whitebox.WhiteBox;

public class TestSVEFeatureDetection {
private static final WhiteBox WB = WhiteBox.getWhiteBox();
private static final String KEY_USE_SVE = "UseSVE=";
private static final String KEY_MAX_VECTOR = "MaxVectorSize=";
private static final String KEY_HAS_SVE = "has_sve=";
private static final String KEY_HAS_SVE2 = "has_sve2=";

public static void main(String[] args) throws Exception {
if (args.length > 0 && args[0].equals("flagCheck")) {
printFlags();
} else {
runDriver();
}
}

private static void printFlags() {
int sveLevel = WB.getUintVMFlag("UseSVE").intValue();
long maxVectorSize = WB.getIntxVMFlag("MaxVectorSize");
List<String> features = Arrays.asList(WB.getCPUFeatures().split(", "));
boolean hasSve = features.contains("sve");
boolean hasSve2 = features.contains("sve2");

System.out.println(KEY_USE_SVE + sveLevel);
System.out.println(KEY_MAX_VECTOR + maxVectorSize);
System.out.println(KEY_HAS_SVE + hasSve);
System.out.println(KEY_HAS_SVE2 + hasSve2);
}

private static void runDriver() throws Exception {
int sveLevel = WB.getUintVMFlag("UseSVE").intValue();
long maxVectorSize = WB.getIntxVMFlag("MaxVectorSize");
List<String> features = Arrays.asList(WB.getCPUFeatures().split(", "));
boolean hasSve = features.contains("sve");
boolean hasSve2 = features.contains("sve2");

// If SVE is not present, just verify a consistent disabled state.
if (!hasSve) {
Asserts.assertEquals(sveLevel, 0,
"UseSVE must be 0 when hardware lacks SVE");
Asserts.assertFalse(hasSve2,
"sve2 must be absent when sve is absent");
return;
}

Asserts.assertTrue(sveLevel > 0,
"UseSVE should be auto-set to > 0 when SVE hardware is present");
Asserts.assertTrue(maxVectorSize >= 16,
"MaxVectorSize must be >= 16 for SVE, got " + maxVectorSize);
Asserts.assertTrue(Long.bitCount(maxVectorSize) == 1,
"MaxVectorSize must be a power of two, got " + maxVectorSize);
Asserts.assertTrue(maxVectorSize % 16 == 0,
"MaxVectorSize must be a multiple of 16, got " + maxVectorSize);
Asserts.assertTrue(maxVectorSize <= 256,
"MaxVectorSize must be <= 256 (2048 bits), got " + maxVectorSize);

if (hasSve2) {
Asserts.assertEquals(sveLevel, 2,
"UseSVE should be 2 when hardware supports SVE2");
} else {
Asserts.assertEquals(sveLevel, 1,
"UseSVE should be 1 when hardware supports SVE but not SVE2");
}

OutputAnalyzer out = spawnFlagCheck("-XX:UseSVE=0");
out.shouldHaveExitValue(0);
out.shouldContain(KEY_USE_SVE + "0");
out.shouldContain(KEY_HAS_SVE + "false");
out.shouldContain(KEY_HAS_SVE2 + "false");

out = spawnFlagCheck("-XX:UseSVE=1", "-XX:MaxVectorSize=512");
out.shouldHaveExitValue(0);
out.shouldContain("warning");

boolean isWindows = System.getProperty("os.name").toLowerCase().contains("windows");
out = spawnFlagCheck("-XX:UseSVE=1", "-XX:MaxVectorSize=16");
out.shouldHaveExitValue(0);
if (isWindows && maxVectorSize > 16) {
out.shouldContain("warning");
out.shouldContain(KEY_MAX_VECTOR + maxVectorSize);
} else {
out.shouldContain(KEY_MAX_VECTOR + "16");
}

if (hasSve2) {
out = spawnFlagCheck("-XX:UseSVE=2");
out.shouldHaveExitValue(0);
out.shouldContain(KEY_USE_SVE + "2");
out.shouldContain(KEY_HAS_SVE + "true");
out.shouldContain(KEY_HAS_SVE2 + "true");

out = spawnFlagCheck("-XX:UseSVE=1");
out.shouldHaveExitValue(0);
out.shouldContain(KEY_USE_SVE + "1");
out.shouldContain(KEY_HAS_SVE + "true");
out.shouldContain(KEY_HAS_SVE2 + "false");
} else {
out = spawnFlagCheck("-XX:UseSVE=2");
out.shouldHaveExitValue(0);
out.shouldContain("SVE2 specified, but not supported on current CPU");
out.shouldContain(KEY_USE_SVE + "1");
out.shouldContain(KEY_HAS_SVE + "true");
out.shouldContain(KEY_HAS_SVE2 + "false");
}

out = spawnFlagCheck("-XX:UseSVE=1");
out.shouldHaveExitValue(0);
out.shouldContain(KEY_USE_SVE + "1");
out.shouldContain(KEY_HAS_SVE + "true");
out.shouldMatch("MaxVectorSize=\\d+");

if (maxVectorSize >= 32) {
out = spawnFlagCheck("-XX:UseSVE=1", "-XX:MaxVectorSize=32");
out.shouldHaveExitValue(0);
if (isWindows && maxVectorSize > 32) {
out.shouldContain("warning");
out.shouldContain(KEY_MAX_VECTOR + maxVectorSize);
} else {
out.shouldContain(KEY_MAX_VECTOR + "32");
}
}
}

private static OutputAnalyzer spawnFlagCheck(String... extraFlags)
throws Exception {
List<String> args = new ArrayList<>();
args.add("-Xbootclasspath/a:.");
args.add("-XX:+UnlockDiagnosticVMOptions");
args.add("-XX:+WhiteBoxAPI");
for (String f : extraFlags) {
args.add(f);
}
args.add(TestSVEFeatureDetection.class.getName());
args.add("flagCheck");

ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(
args.toArray(new String[0]));
OutputAnalyzer output = new OutputAnalyzer(pb.start());
output.reportDiagnosticSummary();
return output;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -714,9 +714,13 @@ public void testSqrtConstantFolding() {

@Test
@IR(counts = {IRNode.FMA_HF, " 0 ", IRNode.REINTERPRET_S2HF, " 0 ", IRNode.REINTERPRET_HF2S, " 0 "},
applyIfCPUFeatureOr = {"avx512_fp16", "true", "zfh", "true"})
applyIfCPUFeatureOr = {"avx512_fp16", "true", "zfh", "true"},
// On Windows, both GCC and MSVC don't set __STDC_IEC_559__, so FMAs on constants are not folded.
applyIfPlatform = {"windows", "false"})
@IR(counts = {IRNode.FMA_HF, " 0 ", IRNode.REINTERPRET_S2HF, " 0 ", IRNode.REINTERPRET_HF2S, " 0 "},
applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"})
applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"},
// On Windows, both GCC and MSVC don't set __STDC_IEC_559__, so FMAs on constants are not folded.
applyIfPlatform = {"windows", "false"})
@Warmup(10000)
public void testFMAConstantFolding() {
// If any argument is NaN, the result is NaN.
Expand Down Expand Up @@ -752,9 +756,13 @@ public void testFMAConstantFolding() {

@Test
@IR(failOn = {IRNode.ADD_HF, IRNode.SUB_HF, IRNode.MUL_HF, IRNode.DIV_HF, IRNode.SQRT_HF, IRNode.FMA_HF},
applyIfCPUFeatureOr = {"avx512_fp16", "true", "zfh", "true"})
applyIfCPUFeatureOr = {"avx512_fp16", "true", "zfh", "true"},
// On Windows, both GCC and MSVC don't set __STDC_IEC_559__, so FMAs on constants are not folded.
applyIfPlatform = {"windows", "false"})
@IR(failOn = {IRNode.ADD_HF, IRNode.SUB_HF, IRNode.MUL_HF, IRNode.DIV_HF, IRNode.SQRT_HF, IRNode.FMA_HF},
applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"})
applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"},
// On Windows, both GCC and MSVC don't set __STDC_IEC_559__, so FMAs on constants are not folded.
applyIfPlatform = {"windows", "false"})
@Warmup(10000)
public void testRounding1() {
dst[0] = float16ToRawShortBits(add(RANDOM1, RANDOM2));
Expand Down
Loading