From 6c5a2609f0e845cd620ae72ce723ebe3a1dfc3cb Mon Sep 17 00:00:00 2001 From: thomthehound Date: Mon, 2 Mar 2026 15:26:09 -0500 Subject: [PATCH 1/2] Windows: Preliminary lit tooling pass Signed-off-by: thomthehound --- mlir_exercises/lit.site.cfg.py.in | 76 ++++++------ programming_examples/lit.site.cfg.py.in | 96 +++++++-------- programming_guide/lit.site.cfg.py.in | 96 +++++++-------- python/aie_lit_utils/lit_config_helpers.py | 135 ++++++++++++++++++--- test/CMakeLists.txt | 4 + test/lit.cfg.py | 21 +++- test/lit.site.cfg.py.in | 102 ++++++++-------- utils/run_on_npu.py | 44 +++++++ 8 files changed, 369 insertions(+), 205 deletions(-) create mode 100644 utils/run_on_npu.py diff --git a/mlir_exercises/lit.site.cfg.py.in b/mlir_exercises/lit.site.cfg.py.in index a2e11168c1d..343496b20af 100755 --- a/mlir_exercises/lit.site.cfg.py.in +++ b/mlir_exercises/lit.site.cfg.py.in @@ -11,53 +11,53 @@ import sys import lit.util -config.host_triple = "@LLVM_HOST_TRIPLE@" -config.target_triple = "@TARGET_TRIPLE@" -config.llvm_src_root = "@LLVM_SOURCE_DIR@" -config.llvm_obj_root = "@LLVM_BINARY_DIR@" -config.llvm_tools_dir = "@LLVM_TOOLS_DIR@" -config.llvm_lib_dir = "@LLVM_LIBRARY_DIR@" -config.llvm_shlib_dir = "@SHLIBDIR@" -config.llvm_shlib_ext = "@SHLIBEXT@" -config.llvm_exe_ext = "@EXEEXT@" -config.peano_install_dir = "@PEANO_INSTALL_DIR@" -config.lit_tools_dir = "@LLVM_LIT_TOOLS_DIR@" -config.python_executable = "@Python3_EXECUTABLE@" -config.gold_executable = "@GOLD_EXECUTABLE@" -config.ld64_executable = "@LD64_EXECUTABLE@" +config.host_triple = r"""@LLVM_HOST_TRIPLE@""" +config.target_triple = r"""@TARGET_TRIPLE@""" +config.llvm_src_root = r"""@LLVM_SOURCE_DIR@""" +config.llvm_obj_root = r"""@LLVM_BINARY_DIR@""" +config.llvm_tools_dir = r"""@LLVM_TOOLS_DIR@""" +config.llvm_lib_dir = r"""@LLVM_LIBRARY_DIR@""" +config.llvm_shlib_dir = r"""@SHLIBDIR@""" +config.llvm_shlib_ext = r"""@SHLIBEXT@""" +config.llvm_exe_ext = r"""@EXEEXT@""" +config.peano_install_dir = r"""@PEANO_INSTALL_DIR@""" +config.lit_tools_dir = r"""@LLVM_LIT_TOOLS_DIR@""" +config.python_executable = r"""@Python3_EXECUTABLE@""" +config.gold_executable = r"""@GOLD_EXECUTABLE@""" +config.ld64_executable = r"""@LD64_EXECUTABLE@""" config.enable_shared = @ENABLE_SHARED@ config.enable_assertions = @ENABLE_ASSERTIONS@ -config.targets_to_build = "@TARGETS_TO_BUILD@" -config.native_target = "@LLVM_NATIVE_ARCH@" -config.llvm_bindings = "@LLVM_BINDINGS@".split(' ') -config.host_os = "@HOST_OS@" -config.host_cc = "@HOST_CC@" -config.host_cxx = "@HOST_CXX@" -# Note: ldflags can contain double-quoted paths, so must use single quotes here. -config.host_ldflags = '@HOST_LDFLAGS@' -config.llvm_use_sanitizer = "@LLVM_USE_SANITIZER@" -config.llvm_host_triple = '@LLVM_HOST_TRIPLE@' -config.host_arch = "@HOST_ARCH@" +config.targets_to_build = r"""@TARGETS_TO_BUILD@""" +config.native_target = r"""@LLVM_NATIVE_ARCH@""" +config.llvm_bindings = r"""@LLVM_BINDINGS@""".split(' ') +config.host_os = r"""@HOST_OS@""" +config.host_cc = r"""@HOST_CC@""" +config.host_cxx = r"""@HOST_CXX@""" +# Use a raw triple-quoted string so Windows backslashes and embedded quotes survive. +config.host_ldflags = r"""@HOST_LDFLAGS@""" +config.llvm_use_sanitizer = r"""@LLVM_USE_SANITIZER@""" +config.llvm_host_triple = r"""@LLVM_HOST_TRIPLE@""" +config.host_arch = r"""@HOST_ARCH@""" -config.aie_src_root = "@AIE_SOURCE_DIR@" -config.aie_obj_root = "@AIE_BINARY_DIR@" +config.aie_src_root = r"""@AIE_SOURCE_DIR@""" +config.aie_obj_root = r"""@AIE_BINARY_DIR@""" # test_exec_root: The root path where tests should be run. -config.test_exec_root = "@CMAKE_CURRENT_BINARY_DIR@" +config.test_exec_root = r"""@CMAKE_CURRENT_BINARY_DIR@""" # pass on vitis settings config.enable_chess_tests = @CONFIG_ENABLE_CHESS_TESTS@ config.enable_board_tests = @CONFIG_ENABLE_BOARD_TESTS@ -config.vitis_root = "@VITIS_ROOT@" -config.vitis_aietools_dir = "@VITIS_AIETOOLS_DIR@" -config.vitis_sysroot = "@Sysroot@" -config.extraAieCcFlags = "@extraAieCcFlags@" -config.aieHostTarget = "@AIE_RUNTIME_TEST_TARGET@" -config.aieInstallPrefix = "@CMAKE_INSTALL_PREFIX@" +config.vitis_root = r"""@VITIS_ROOT@""" +config.vitis_aietools_dir = r"""@VITIS_AIETOOLS_DIR@""" +config.vitis_sysroot = r"""@Sysroot@""" +config.extraAieCcFlags = r"""@extraAieCcFlags@""" +config.aieHostTarget = r"""@AIE_RUNTIME_TEST_TARGET@""" +config.aieInstallPrefix = r"""@CMAKE_INSTALL_PREFIX@""" config.vitis_components = [] -if lit.util.pythonize_bool("@AIETools_AIE_FOUND@"): +if lit.util.pythonize_bool(r"""@AIETools_AIE_FOUND@"""): config.vitis_components.append("AIE") -if lit.util.pythonize_bool("@AIETools_AIE2_FOUND@"): +if lit.util.pythonize_bool(r"""@AIETools_AIE2_FOUND@"""): config.vitis_components.append("AIE2") # Support substitution of the tools_dir with user parameters. This is @@ -70,10 +70,10 @@ except KeyError: key, = e.args lit_config.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key,key)) -config.aie_include_integration_tests = "@AIE_INCLUDE_INTEGRATION_TESTS@" +config.aie_include_integration_tests = r"""@AIE_INCLUDE_INTEGRATION_TESTS@""" import lit.llvm lit.llvm.initialize(lit_config, config) # Let the main config do the real work. -lit_config.load_config(config, "@PROJECT_SOURCE_DIR@/lit.cfg.py") +lit_config.load_config(config, r"""@PROJECT_SOURCE_DIR@/lit.cfg.py""") diff --git a/programming_examples/lit.site.cfg.py.in b/programming_examples/lit.site.cfg.py.in index 3ba7a457f11..ca6152bd98f 100755 --- a/programming_examples/lit.site.cfg.py.in +++ b/programming_examples/lit.site.cfg.py.in @@ -11,65 +11,65 @@ import sys import lit.util -config.host_triple = "@LLVM_HOST_TRIPLE@" -config.target_triple = "@TARGET_TRIPLE@" -config.llvm_src_root = "@LLVM_SOURCE_DIR@" -config.llvm_obj_root = "@LLVM_BINARY_DIR@" -config.llvm_tools_dir = "@LLVM_TOOLS_DIR@" -config.llvm_lib_dir = "@LLVM_LIBRARY_DIR@" -config.llvm_shlib_dir = "@SHLIBDIR@" -config.llvm_shlib_ext = "@SHLIBEXT@" -config.llvm_exe_ext = "@EXEEXT@" -config.peano_install_dir = "@PEANO_INSTALL_DIR@" -config.lit_tools_dir = "@LLVM_LIT_TOOLS_DIR@" -config.python_executable = "@Python3_EXECUTABLE@" -config.gold_executable = "@GOLD_EXECUTABLE@" -config.ld64_executable = "@LD64_EXECUTABLE@" +config.host_triple = r"""@LLVM_HOST_TRIPLE@""" +config.target_triple = r"""@TARGET_TRIPLE@""" +config.llvm_src_root = r"""@LLVM_SOURCE_DIR@""" +config.llvm_obj_root = r"""@LLVM_BINARY_DIR@""" +config.llvm_tools_dir = r"""@LLVM_TOOLS_DIR@""" +config.llvm_lib_dir = r"""@LLVM_LIBRARY_DIR@""" +config.llvm_shlib_dir = r"""@SHLIBDIR@""" +config.llvm_shlib_ext = r"""@SHLIBEXT@""" +config.llvm_exe_ext = r"""@EXEEXT@""" +config.peano_install_dir = r"""@PEANO_INSTALL_DIR@""" +config.lit_tools_dir = r"""@LLVM_LIT_TOOLS_DIR@""" +config.python_executable = r"""@Python3_EXECUTABLE@""" +config.gold_executable = r"""@GOLD_EXECUTABLE@""" +config.ld64_executable = r"""@LD64_EXECUTABLE@""" config.enable_shared = @ENABLE_SHARED@ config.enable_assertions = @ENABLE_ASSERTIONS@ -config.targets_to_build = "@TARGETS_TO_BUILD@" -config.native_target = "@LLVM_NATIVE_ARCH@" -config.llvm_bindings = "@LLVM_BINDINGS@".split(' ') -config.host_os = "@HOST_OS@" -config.host_cc = "@HOST_CC@" -config.host_cxx = "@HOST_CXX@" -# Note: ldflags can contain double-quoted paths, so must use single quotes here. -config.host_ldflags = '@HOST_LDFLAGS@' -config.llvm_use_sanitizer = "@LLVM_USE_SANITIZER@" -config.llvm_host_triple = '@LLVM_HOST_TRIPLE@' -config.host_arch = "@HOST_ARCH@" -config.xrt_dir = "@XRT_DIR@" -config.xrt_bin_dir = "@XRT_BIN_DIR@" -config.xrt_lib_dir = "@XRT_LIB_DIR@" -config.xrt_include_dir = "@XRT_INCLUDE_DIR@" -config.opencv_libs = "@OpenCV_LIBS@" -config.opencv_lib_dir = "@OpenCV_LIB_PATH@" -config.opencv_include_dir = "@OpenCV_INCLUDE_DIRS@" +config.targets_to_build = r"""@TARGETS_TO_BUILD@""" +config.native_target = r"""@LLVM_NATIVE_ARCH@""" +config.llvm_bindings = r"""@LLVM_BINDINGS@""".split(' ') +config.host_os = r"""@HOST_OS@""" +config.host_cc = r"""@HOST_CC@""" +config.host_cxx = r"""@HOST_CXX@""" +# Use a raw triple-quoted string so Windows backslashes and embedded quotes survive. +config.host_ldflags = r"""@HOST_LDFLAGS@""" +config.llvm_use_sanitizer = r"""@LLVM_USE_SANITIZER@""" +config.llvm_host_triple = r"""@LLVM_HOST_TRIPLE@""" +config.host_arch = r"""@HOST_ARCH@""" +config.xrt_dir = r"""@XRT_DIR@""" +config.xrt_bin_dir = r"""@XRT_BIN_DIR@""" +config.xrt_lib_dir = r"""@XRT_LIB_DIR@""" +config.xrt_include_dir = r"""@XRT_INCLUDE_DIR@""" +config.opencv_libs = r"""@OpenCV_LIBS@""" +config.opencv_lib_dir = r"""@OpenCV_LIB_PATH@""" +config.opencv_include_dir = r"""@OpenCV_INCLUDE_DIRS@""" -config.aie_src_root = "@AIE_SOURCE_DIR@" -config.aie_obj_root = "@AIE_BINARY_DIR@" +config.aie_src_root = r"""@AIE_SOURCE_DIR@""" +config.aie_obj_root = r"""@AIE_BINARY_DIR@""" # test_exec_root: The root path where tests should be run. -config.test_exec_root = "@CMAKE_CURRENT_BINARY_DIR@" +config.test_exec_root = r"""@CMAKE_CURRENT_BINARY_DIR@""" -config.hsa_dir = "@hsa-runtime64_DIR@" -config.hsa_found = lit.util.pythonize_bool("@hsa-runtime64_FOUND@") +config.hsa_dir = r"""@hsa-runtime64_DIR@""" +config.hsa_found = lit.util.pythonize_bool(r"""@hsa-runtime64_FOUND@""") # pass on vitis settings config.enable_chess_tests = @CONFIG_ENABLE_CHESS_TESTS@ config.enable_board_tests = @CONFIG_ENABLE_BOARD_TESTS@ -config.vitis_root = "@VITIS_ROOT@" -config.vitis_aietools_dir = "@VITIS_AIETOOLS_DIR@" -config.vitis_sysroot = "@Sysroot@" -config.extraAieCcFlags = "@extraAieCcFlags@" -config.aieHostTarget = "@AIE_RUNTIME_TEST_TARGET@" -config.aieInstallPrefix = "@CMAKE_INSTALL_PREFIX@" +config.vitis_root = r"""@VITIS_ROOT@""" +config.vitis_aietools_dir = r"""@VITIS_AIETOOLS_DIR@""" +config.vitis_sysroot = r"""@Sysroot@""" +config.extraAieCcFlags = r"""@extraAieCcFlags@""" +config.aieHostTarget = r"""@AIE_RUNTIME_TEST_TARGET@""" +config.aieInstallPrefix = r"""@CMAKE_INSTALL_PREFIX@""" config.vitis_components = [] -if lit.util.pythonize_bool("@AIETools_AIE_FOUND@"): +if lit.util.pythonize_bool(r"""@AIETools_AIE_FOUND@"""): config.vitis_components.append("AIE") -if lit.util.pythonize_bool("@AIETools_AIE2_FOUND@"): +if lit.util.pythonize_bool(r"""@AIETools_AIE2_FOUND@"""): config.vitis_components.append("AIE2") -if lit.util.pythonize_bool("@AIETools_AIE2P_FOUND@"): +if lit.util.pythonize_bool(r"""@AIETools_AIE2P_FOUND@"""): config.vitis_components.append("AIE2P") # Support substitution of the tools_dir with user parameters. This is @@ -82,10 +82,10 @@ except KeyError: key, = e.args lit_config.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key,key)) -config.aie_include_integration_tests = "@AIE_INCLUDE_INTEGRATION_TESTS@" +config.aie_include_integration_tests = r"""@AIE_INCLUDE_INTEGRATION_TESTS@""" import lit.llvm lit.llvm.initialize(lit_config, config) # Let the main config do the real work. -lit_config.load_config(config, "@PROJECT_SOURCE_DIR@/lit.cfg.py") +lit_config.load_config(config, r"""@PROJECT_SOURCE_DIR@/lit.cfg.py""") diff --git a/programming_guide/lit.site.cfg.py.in b/programming_guide/lit.site.cfg.py.in index 3ba7a457f11..ca6152bd98f 100755 --- a/programming_guide/lit.site.cfg.py.in +++ b/programming_guide/lit.site.cfg.py.in @@ -11,65 +11,65 @@ import sys import lit.util -config.host_triple = "@LLVM_HOST_TRIPLE@" -config.target_triple = "@TARGET_TRIPLE@" -config.llvm_src_root = "@LLVM_SOURCE_DIR@" -config.llvm_obj_root = "@LLVM_BINARY_DIR@" -config.llvm_tools_dir = "@LLVM_TOOLS_DIR@" -config.llvm_lib_dir = "@LLVM_LIBRARY_DIR@" -config.llvm_shlib_dir = "@SHLIBDIR@" -config.llvm_shlib_ext = "@SHLIBEXT@" -config.llvm_exe_ext = "@EXEEXT@" -config.peano_install_dir = "@PEANO_INSTALL_DIR@" -config.lit_tools_dir = "@LLVM_LIT_TOOLS_DIR@" -config.python_executable = "@Python3_EXECUTABLE@" -config.gold_executable = "@GOLD_EXECUTABLE@" -config.ld64_executable = "@LD64_EXECUTABLE@" +config.host_triple = r"""@LLVM_HOST_TRIPLE@""" +config.target_triple = r"""@TARGET_TRIPLE@""" +config.llvm_src_root = r"""@LLVM_SOURCE_DIR@""" +config.llvm_obj_root = r"""@LLVM_BINARY_DIR@""" +config.llvm_tools_dir = r"""@LLVM_TOOLS_DIR@""" +config.llvm_lib_dir = r"""@LLVM_LIBRARY_DIR@""" +config.llvm_shlib_dir = r"""@SHLIBDIR@""" +config.llvm_shlib_ext = r"""@SHLIBEXT@""" +config.llvm_exe_ext = r"""@EXEEXT@""" +config.peano_install_dir = r"""@PEANO_INSTALL_DIR@""" +config.lit_tools_dir = r"""@LLVM_LIT_TOOLS_DIR@""" +config.python_executable = r"""@Python3_EXECUTABLE@""" +config.gold_executable = r"""@GOLD_EXECUTABLE@""" +config.ld64_executable = r"""@LD64_EXECUTABLE@""" config.enable_shared = @ENABLE_SHARED@ config.enable_assertions = @ENABLE_ASSERTIONS@ -config.targets_to_build = "@TARGETS_TO_BUILD@" -config.native_target = "@LLVM_NATIVE_ARCH@" -config.llvm_bindings = "@LLVM_BINDINGS@".split(' ') -config.host_os = "@HOST_OS@" -config.host_cc = "@HOST_CC@" -config.host_cxx = "@HOST_CXX@" -# Note: ldflags can contain double-quoted paths, so must use single quotes here. -config.host_ldflags = '@HOST_LDFLAGS@' -config.llvm_use_sanitizer = "@LLVM_USE_SANITIZER@" -config.llvm_host_triple = '@LLVM_HOST_TRIPLE@' -config.host_arch = "@HOST_ARCH@" -config.xrt_dir = "@XRT_DIR@" -config.xrt_bin_dir = "@XRT_BIN_DIR@" -config.xrt_lib_dir = "@XRT_LIB_DIR@" -config.xrt_include_dir = "@XRT_INCLUDE_DIR@" -config.opencv_libs = "@OpenCV_LIBS@" -config.opencv_lib_dir = "@OpenCV_LIB_PATH@" -config.opencv_include_dir = "@OpenCV_INCLUDE_DIRS@" +config.targets_to_build = r"""@TARGETS_TO_BUILD@""" +config.native_target = r"""@LLVM_NATIVE_ARCH@""" +config.llvm_bindings = r"""@LLVM_BINDINGS@""".split(' ') +config.host_os = r"""@HOST_OS@""" +config.host_cc = r"""@HOST_CC@""" +config.host_cxx = r"""@HOST_CXX@""" +# Use a raw triple-quoted string so Windows backslashes and embedded quotes survive. +config.host_ldflags = r"""@HOST_LDFLAGS@""" +config.llvm_use_sanitizer = r"""@LLVM_USE_SANITIZER@""" +config.llvm_host_triple = r"""@LLVM_HOST_TRIPLE@""" +config.host_arch = r"""@HOST_ARCH@""" +config.xrt_dir = r"""@XRT_DIR@""" +config.xrt_bin_dir = r"""@XRT_BIN_DIR@""" +config.xrt_lib_dir = r"""@XRT_LIB_DIR@""" +config.xrt_include_dir = r"""@XRT_INCLUDE_DIR@""" +config.opencv_libs = r"""@OpenCV_LIBS@""" +config.opencv_lib_dir = r"""@OpenCV_LIB_PATH@""" +config.opencv_include_dir = r"""@OpenCV_INCLUDE_DIRS@""" -config.aie_src_root = "@AIE_SOURCE_DIR@" -config.aie_obj_root = "@AIE_BINARY_DIR@" +config.aie_src_root = r"""@AIE_SOURCE_DIR@""" +config.aie_obj_root = r"""@AIE_BINARY_DIR@""" # test_exec_root: The root path where tests should be run. -config.test_exec_root = "@CMAKE_CURRENT_BINARY_DIR@" +config.test_exec_root = r"""@CMAKE_CURRENT_BINARY_DIR@""" -config.hsa_dir = "@hsa-runtime64_DIR@" -config.hsa_found = lit.util.pythonize_bool("@hsa-runtime64_FOUND@") +config.hsa_dir = r"""@hsa-runtime64_DIR@""" +config.hsa_found = lit.util.pythonize_bool(r"""@hsa-runtime64_FOUND@""") # pass on vitis settings config.enable_chess_tests = @CONFIG_ENABLE_CHESS_TESTS@ config.enable_board_tests = @CONFIG_ENABLE_BOARD_TESTS@ -config.vitis_root = "@VITIS_ROOT@" -config.vitis_aietools_dir = "@VITIS_AIETOOLS_DIR@" -config.vitis_sysroot = "@Sysroot@" -config.extraAieCcFlags = "@extraAieCcFlags@" -config.aieHostTarget = "@AIE_RUNTIME_TEST_TARGET@" -config.aieInstallPrefix = "@CMAKE_INSTALL_PREFIX@" +config.vitis_root = r"""@VITIS_ROOT@""" +config.vitis_aietools_dir = r"""@VITIS_AIETOOLS_DIR@""" +config.vitis_sysroot = r"""@Sysroot@""" +config.extraAieCcFlags = r"""@extraAieCcFlags@""" +config.aieHostTarget = r"""@AIE_RUNTIME_TEST_TARGET@""" +config.aieInstallPrefix = r"""@CMAKE_INSTALL_PREFIX@""" config.vitis_components = [] -if lit.util.pythonize_bool("@AIETools_AIE_FOUND@"): +if lit.util.pythonize_bool(r"""@AIETools_AIE_FOUND@"""): config.vitis_components.append("AIE") -if lit.util.pythonize_bool("@AIETools_AIE2_FOUND@"): +if lit.util.pythonize_bool(r"""@AIETools_AIE2_FOUND@"""): config.vitis_components.append("AIE2") -if lit.util.pythonize_bool("@AIETools_AIE2P_FOUND@"): +if lit.util.pythonize_bool(r"""@AIETools_AIE2P_FOUND@"""): config.vitis_components.append("AIE2P") # Support substitution of the tools_dir with user parameters. This is @@ -82,10 +82,10 @@ except KeyError: key, = e.args lit_config.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key,key)) -config.aie_include_integration_tests = "@AIE_INCLUDE_INTEGRATION_TESTS@" +config.aie_include_integration_tests = r"""@AIE_INCLUDE_INTEGRATION_TESTS@""" import lit.llvm lit.llvm.initialize(lit_config, config) # Let the main config do the real work. -lit_config.load_config(config, "@PROJECT_SOURCE_DIR@/lit.cfg.py") +lit_config.load_config(config, r"""@PROJECT_SOURCE_DIR@/lit.cfg.py""") diff --git a/python/aie_lit_utils/lit_config_helpers.py b/python/aie_lit_utils/lit_config_helpers.py index 77236bf159c..00c4940542e 100644 --- a/python/aie_lit_utils/lit_config_helpers.py +++ b/python/aie_lit_utils/lit_config_helpers.py @@ -29,6 +29,7 @@ import re import shutil import subprocess +import sys from typing import Dict, List, Optional, Tuple from dataclasses import dataclass, field @@ -63,6 +64,73 @@ class LitConfigHelper: "npu2": ["npu4", "Strix", "npu5", "Strix Halo", "npu6", "Krackan"], } + PATH_ENV_VARS = {"PATH", "LD_LIBRARY_PATH", "DYLD_LIBRARY_PATH"} + + @staticmethod + def _prepend_env_paths(current_value: str, new_value: str) -> str: + """Prepend path entries without overwriting the existing values.""" + entries = [] + for value in (new_value, current_value): + if not value: + continue + entries.extend([entry for entry in value.split(os.path.pathsep) if entry]) + + merged = [] + seen = set() + for entry in entries: + normalized = os.path.normcase(os.path.normpath(entry)) + if normalized in seen: + continue + seen.add(normalized) + merged.append(entry) + return os.path.pathsep.join(merged) + + @staticmethod + def _quote_lit_arg(value: str) -> str: + """Quote arguments for lit's shell parser.""" + return "\"" + value.replace("\\", "/").replace("\"", "\\\"") + "\"" + + @staticmethod + def _run_on_npu_wrap(aie_src_root: str, npu_kind: str) -> str: + """Build the cross-platform run-on-NPU wrapper command.""" + wrapper = os.path.join(aie_src_root, "utils", "run_on_npu.py") + return " ".join( + [ + LitConfigHelper._quote_lit_arg(sys.executable), + LitConfigHelper._quote_lit_arg(wrapper), + LitConfigHelper._quote_lit_arg(npu_kind), + ] + ) + + @staticmethod + def _find_xrt_smi(xrt_bin_dir: str) -> Optional[str]: + """Find xrt-smi without assuming it exists under XRT_ROOT.""" + candidates = [] + if xrt_bin_dir: + candidates.extend( + [ + os.path.join(xrt_bin_dir, "xrt-smi"), + os.path.join(xrt_bin_dir, "bin", "xrt-smi"), + ] + ) + if os.name == "nt": + candidates.extend( + [ + os.path.join(xrt_bin_dir, "xrt-smi.exe"), + os.path.join(xrt_bin_dir, "bin", "xrt-smi.exe"), + ] + ) + + if os.name == "nt": + system_root = os.environ.get("SystemRoot", r"C:\Windows") + candidates.append(os.path.join(system_root, "System32", "AMD", "xrt-smi.exe")) + + for candidate in candidates: + if os.path.isfile(candidate): + return candidate + + return shutil.which("xrt-smi") + @staticmethod def prepend_path(llvm_config, path: str) -> None: """ @@ -186,7 +254,7 @@ def detect_xrt( xrt_lib_dir: Path to XRT library directory xrt_include_dir: Path to XRT include directory xrt_bin_dir: Path to XRT binary directory - aie_src_root: Path to AIE source root (for run_on_npu.sh script) + aie_src_root: Path to AIE source root (for the run_on_npu wrapper) vitis_components: List of available Vitis components for feature filtering Returns: @@ -216,27 +284,50 @@ def detect_xrt( print(f"xrt found at {os.path.dirname(xrt_lib_dir)}") config.found = True - config.flags = f"-I{xrt_include_dir} -L{xrt_lib_dir} -luuid -lxrt_coreutil" - config.substitutions["%xrt_flags"] = config.flags - # Add XRT library directory to LD_LIBRARY_PATH for runtime linking, - # preserving any existing entries from the parent environment. - existing_ld_library_path = os.environ.get("LD_LIBRARY_PATH") - if existing_ld_library_path: - new_ld_library_path = existing_ld_library_path + os.pathsep + xrt_lib_dir + if os.name == "nt": + config.flags = f"-I{xrt_include_dir} -L{xrt_lib_dir} -lxrt_coreutil" else: - new_ld_library_path = xrt_lib_dir - config.environment["LD_LIBRARY_PATH"] = new_ld_library_path + config.flags = f"-I{xrt_include_dir} -L{xrt_lib_dir} -luuid -lxrt_coreutil" + config.substitutions["%xrt_flags"] = config.flags - # Detect NPU hardware + # Runtime library search path. Compose with the lit environment instead of + # rebuilding PATH/LD_LIBRARY_PATH from the process environment. + if os.name == "nt": + runtime_dirs = [path for path in (xrt_bin_dir, xrt_lib_dir) if path] + if runtime_dirs: + config.environment["PATH"] = os.path.pathsep.join(runtime_dirs) + elif xrt_lib_dir: + config.environment["LD_LIBRARY_PATH"] = xrt_lib_dir + + # Detect NPU hardware. XRT installation layout and xrt-smi location are + # not always the same on Windows, so probe them independently. try: - xrtsmi = os.path.join(xrt_bin_dir, "xrt-smi") + xrtsmi = LitConfigHelper._find_xrt_smi(xrt_bin_dir) + if not xrtsmi: + raise FileNotFoundError("xrt-smi") + + probe_env = os.environ.copy() + for key, value in config.environment.items(): + if key in LitConfigHelper.PATH_ENV_VARS: + probe_env[key] = LitConfigHelper._prepend_env_paths( + probe_env.get(key, ""), value + ) + else: + probe_env[key] = value + + print(f"Using xrt-smi: {xrtsmi}") result = subprocess.run( [xrtsmi, "examine"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, + env=probe_env, timeout=10, ) - output = result.stdout.decode("utf-8", errors="ignore").split("\n") + output = ( + result.stdout.decode("utf-8", errors="ignore") + + "\n" + + result.stderr.decode("utf-8", errors="ignore") + ).split("\n") # Pattern matches both old and new xrt-smi output formats: # Old: "|[0000:41:00.1] ||RyzenAI-npu1 |" @@ -262,12 +353,12 @@ def detect_xrt( print(f"\tmodel: '{model}'") - run_on_npu = f"{aie_src_root}/utils/run_on_npu.sh" - # Map model to NPU generation and filter by available components if model in LitConfigHelper.NPU_MODELS["npu1"]: if "AIE2" in vitis_components: - run_on_npu1 = run_on_npu + run_on_npu1 = LitConfigHelper._run_on_npu_wrap( + aie_src_root, "npu1" + ) config.features.extend(["ryzen_ai", "ryzen_ai_npu1"]) config.substitutions["%run_on_npu1%"] = run_on_npu1 print(f"Running tests on NPU1 with command line: {run_on_npu1}") @@ -275,7 +366,9 @@ def detect_xrt( print("NPU1 detected but aietools for aie2 not available") elif model in LitConfigHelper.NPU_MODELS["npu2"]: if "AIE2P" in vitis_components: - run_on_npu2 = run_on_npu + run_on_npu2 = LitConfigHelper._run_on_npu_wrap( + aie_src_root, "npu2" + ) config.features.extend(["ryzen_ai", "ryzen_ai_npu2"]) config.substitutions["%run_on_npu2%"] = run_on_npu2 print(f"Running tests on NPU2 with command line: {run_on_npu2}") @@ -502,7 +595,13 @@ def apply_config_to_lit(config_obj, hardware_configs: Dict[str, HardwareConfig]) # Add environment variables for key, value in hw_config.environment.items(): - config_obj.environment[key] = value + if key in LitConfigHelper.PATH_ENV_VARS: + current_value = config_obj.environment.get(key, "") + config_obj.environment[key] = LitConfigHelper._prepend_env_paths( + current_value, value + ) + else: + config_obj.environment[key] = value @staticmethod def setup_standard_environment( diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index af6449e64a4..eec7dda8ca3 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -96,6 +96,10 @@ include_directories(${PROJECT_SOURCE_DIR}/include) include_directories(${PROJECT_BINARY_DIR}/include) add_definitions(${LLVM_DEFINITIONS}) +if(WIN32) + file(TO_CMAKE_PATH "${PEANO_INSTALL_DIR}" PEANO_INSTALL_DIR) +endif() + configure_lit_site_cfg( ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.py.in ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg.py diff --git a/test/lit.cfg.py b/test/lit.cfg.py index cd3edd57188..40a9b246e53 100644 --- a/test/lit.cfg.py +++ b/test/lit.cfg.py @@ -137,17 +137,34 @@ tools = [ "aie-opt", "aie-translate", - "aiecc.py", "ld.lld", "llc", "llvm-objdump", "opt", "xchesscc_wrapper", - "txn2mlir.py", ] +if os.name != "nt": + tools.extend(["aiecc.py", "txn2mlir.py"]) + llvm_config.add_tool_substitutions(tools, tool_dirs) +if os.name == "nt": + # Lit on Windows struggles with substituting tools with a .py extension. + # Add these manually and quote them so paths with spaces survive. + config.substitutions.append( + ( + "aiecc.py", + LitConfigHelper._quote_lit_arg(os.path.join(config.aie_tools_dir, "aiecc.py")), + ) + ) + config.substitutions.append( + ( + "txn2mlir.py", + LitConfigHelper._quote_lit_arg(os.path.join(config.aie_tools_dir, "txn2mlir.py")), + ) + ) + if config.enable_board_tests: lit_config.parallelism_groups["board"] = 1 config.parallelism_group = "board" diff --git a/test/lit.site.cfg.py.in b/test/lit.site.cfg.py.in index 94c2c0c2161..1dd0bfccdc2 100644 --- a/test/lit.site.cfg.py.in +++ b/test/lit.site.cfg.py.in @@ -11,69 +11,69 @@ import sys import lit.util -config.host_triple = "@LLVM_HOST_TRIPLE@" -config.target_triple = "@TARGET_TRIPLE@" -config.llvm_src_root = "@LLVM_SOURCE_DIR@" -config.llvm_obj_root = "@LLVM_BINARY_DIR@" -config.llvm_tools_dir = "@LLVM_TOOLS_DIR@" -config.llvm_lib_dir = "@LLVM_LIBRARY_DIR@" -config.llvm_shlib_dir = "@SHLIBDIR@" -config.llvm_shlib_ext = "@SHLIBEXT@" -config.llvm_exe_ext = "@EXEEXT@" -config.peano_install_dir = "@PEANO_INSTALL_DIR@" -config.lit_tools_dir = "@LLVM_LIT_TOOLS_DIR@" -config.python_executable = "@Python3_EXECUTABLE@" -config.gold_executable = "@GOLD_EXECUTABLE@" -config.ld64_executable = "@LD64_EXECUTABLE@" +config.host_triple = r"""@LLVM_HOST_TRIPLE@""" +config.target_triple = r"""@TARGET_TRIPLE@""" +config.llvm_src_root = r"""@LLVM_SOURCE_DIR@""" +config.llvm_obj_root = r"""@LLVM_BINARY_DIR@""" +config.llvm_tools_dir = r"""@LLVM_TOOLS_DIR@""" +config.llvm_lib_dir = r"""@LLVM_LIBRARY_DIR@""" +config.llvm_shlib_dir = r"""@SHLIBDIR@""" +config.llvm_shlib_ext = r"""@SHLIBEXT@""" +config.llvm_exe_ext = r"""@EXEEXT@""" +config.peano_install_dir = r"""@PEANO_INSTALL_DIR@""" +config.lit_tools_dir = r"""@LLVM_LIT_TOOLS_DIR@""" +config.python_executable = r"""@Python3_EXECUTABLE@""" +config.gold_executable = r"""@GOLD_EXECUTABLE@""" +config.ld64_executable = r"""@LD64_EXECUTABLE@""" config.enable_shared = @ENABLE_SHARED@ config.enable_assertions = @ENABLE_ASSERTIONS@ -config.targets_to_build = "@TARGETS_TO_BUILD@" -config.native_target = "@LLVM_NATIVE_ARCH@" -config.llvm_bindings = "@LLVM_BINDINGS@".split(' ') -config.host_os = "@HOST_OS@" -config.host_cc = "@HOST_CC@" -config.host_cxx = "@HOST_CXX@" -# Note: ldflags can contain double-quoted paths, so must use single quotes here. -config.host_ldflags = '@HOST_LDFLAGS@' -config.llvm_use_sanitizer = "@LLVM_USE_SANITIZER@" -config.llvm_host_triple = '@LLVM_HOST_TRIPLE@' -config.host_arch = "@HOST_ARCH@" -config.xrt_dir = "@XRT_DIR@" -config.xrt_bin_dir = "@XRT_BIN_DIR@" -config.xrt_lib_dir = "@XRT_LIB_DIR@" -config.xrt_include_dir = "@XRT_INCLUDE_DIR@" +config.targets_to_build = r"""@TARGETS_TO_BUILD@""" +config.native_target = r"""@LLVM_NATIVE_ARCH@""" +config.llvm_bindings = r"""@LLVM_BINDINGS@""".split(' ') +config.host_os = r"""@HOST_OS@""" +config.host_cc = r"""@HOST_CC@""" +config.host_cxx = r"""@HOST_CXX@""" +# Use a raw triple-quoted string so Windows backslashes and embedded quotes survive. +config.host_ldflags = r"""@HOST_LDFLAGS@""" +config.llvm_use_sanitizer = r"""@LLVM_USE_SANITIZER@""" +config.llvm_host_triple = r"""@LLVM_HOST_TRIPLE@""" +config.host_arch = r"""@HOST_ARCH@""" +config.xrt_dir = r"""@XRT_DIR@""" +config.xrt_bin_dir = r"""@XRT_BIN_DIR@""" +config.xrt_lib_dir = r"""@XRT_LIB_DIR@""" +config.xrt_include_dir = r"""@XRT_INCLUDE_DIR@""" -config.aie_src_root = "@AIE_SOURCE_DIR@" -config.aie_obj_root = "@AIE_BINARY_DIR@" +config.aie_src_root = r"""@AIE_SOURCE_DIR@""" +config.aie_obj_root = r"""@AIE_BINARY_DIR@""" # test_exec_root: The root path where tests should be run. -config.test_exec_root = "@CMAKE_CURRENT_BINARY_DIR@" +config.test_exec_root = r"""@CMAKE_CURRENT_BINARY_DIR@""" # Pointing to the ROCr directories -config.hsa_dir = "@hsa-runtime64_DIR@" -config.hsa_found = "@hsa-runtime64_FOUND@" +config.hsa_dir = r"""@hsa-runtime64_DIR@""" +config.hsa_found = r"""@hsa-runtime64_FOUND@""" # available features -config.enable_chess_tests = lit.util.pythonize_bool("@ENABLE_CHESS_TESTS@") -config.enable_board_tests = lit.util.pythonize_bool("@ENABLE_BOARD_TESTS@") -config.enable_python_tests = lit.util.pythonize_bool("@ENABLE_PYTHON_TESTS@") -config.python_passes = lit.util.pythonize_bool("@AIE_ENABLE_PYTHON_PASSES@") -config.xrt_python_bindings = lit.util.pythonize_bool("@AIE_ENABLE_XRT_PYTHON_BINDINGS@") -config.has_mlir_runtime_libraries = lit.util.pythonize_bool("@HAS_MLIR_RUNTIME_LIBRARIES@") +config.enable_chess_tests = lit.util.pythonize_bool(r"""@ENABLE_CHESS_TESTS@""") +config.enable_board_tests = lit.util.pythonize_bool(r"""@ENABLE_BOARD_TESTS@""") +config.enable_python_tests = lit.util.pythonize_bool(r"""@ENABLE_PYTHON_TESTS@""") +config.python_passes = lit.util.pythonize_bool(r"""@AIE_ENABLE_PYTHON_PASSES@""") +config.xrt_python_bindings = lit.util.pythonize_bool(r"""@AIE_ENABLE_XRT_PYTHON_BINDINGS@""") +config.has_mlir_runtime_libraries = lit.util.pythonize_bool(r"""@HAS_MLIR_RUNTIME_LIBRARIES@""") # pass on vitis settings -config.vitis_root = "@VITIS_ROOT@" -config.vitis_aietools_dir = "@VITIS_AIETOOLS_DIR@" -config.vitis_sysroot = "@Sysroot@" -config.extraAieCcFlags = "@extraAieCcFlags@" -config.aieHostTarget = "@AIE_RUNTIME_TEST_TARGET@" -config.aieInstallPrefix = "@CMAKE_INSTALL_PREFIX@" +config.vitis_root = r"""@VITIS_ROOT@""" +config.vitis_aietools_dir = r"""@VITIS_AIETOOLS_DIR@""" +config.vitis_sysroot = r"""@Sysroot@""" +config.extraAieCcFlags = r"""@extraAieCcFlags@""" +config.aieHostTarget = r"""@AIE_RUNTIME_TEST_TARGET@""" +config.aieInstallPrefix = r"""@CMAKE_INSTALL_PREFIX@""" config.vitis_components = [] -if lit.util.pythonize_bool("@AIETools_AIE_FOUND@"): +if lit.util.pythonize_bool(r"""@AIETools_AIE_FOUND@"""): config.vitis_components.append("AIE") -if lit.util.pythonize_bool("@AIETools_AIE2_FOUND@"): +if lit.util.pythonize_bool(r"""@AIETools_AIE2_FOUND@"""): config.vitis_components.append("AIE2") -if lit.util.pythonize_bool("@AIETools_AIE2P_FOUND@"): +if lit.util.pythonize_bool(r"""@AIETools_AIE2P_FOUND@"""): config.vitis_components.append("AIE2P") # Support substitution of the tools_dir with user parameters. This is @@ -86,10 +86,10 @@ except KeyError: key, = e.args lit_config.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key,key)) -config.aie_include_integration_tests = "@AIE_INCLUDE_INTEGRATION_TESTS@" +config.aie_include_integration_tests = r"""@AIE_INCLUDE_INTEGRATION_TESTS@""" import lit.llvm lit.llvm.initialize(lit_config, config) # Let the main config do the real work. -lit_config.load_config(config, "@PROJECT_SOURCE_DIR@/lit.cfg.py") +lit_config.load_config(config, r"""@PROJECT_SOURCE_DIR@/lit.cfg.py""") diff --git a/utils/run_on_npu.py b/utils/run_on_npu.py new file mode 100644 index 00000000000..6559343aa73 --- /dev/null +++ b/utils/run_on_npu.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python3 + +# (c) Copyright 2023-2026 Advanced Micro Devices, Inc. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +import os +import subprocess +import sys + + +def main() -> int: + if len(sys.argv) < 3: + print("usage: run_on_npu.py [args...]", file=sys.stderr) + return 2 + + # Mimic the existing %run_on_npu*% bash functionality, broadening OS support. + # "NPU kind" is currently informational only. + _npu_kind = sys.argv[1] + command = sys.argv[2:] + + if os.name == "nt": + completed = subprocess.run(command) + return completed.returncode + + xrt_dir = os.environ.get("XRT_DIR") or os.environ.get("XRT_ROOT") or "/opt/xilinx/xrt" + setup_script = os.path.join(xrt_dir, "setup.sh") + if not os.path.isfile(setup_script): + completed = subprocess.run(command) + return completed.returncode + + bash_command = [ + "bash", + "-lc", + 'source "$1" >/dev/null 2>&1; shift; exec "$@"', + "run_on_npu", + setup_script, + *command, + ] + completed = subprocess.run(bash_command) + return completed.returncode + + +if __name__ == "__main__": + raise SystemExit(main()) From 1f6a2223a81a630d6852f4b8dec497b5eebfe336 Mon Sep 17 00:00:00 2001 From: thomthehound Date: Mon, 2 Mar 2026 17:33:33 -0500 Subject: [PATCH 2/2] lock and serliaze NPU runners Signed-off-by: thomthehound --- python/aie_lit_utils/lit_config_helpers.py | 6 ++++-- test/lit.cfg.py | 8 ++++++-- utils/run_on_npu.py | 21 +++++++++++++++------ 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/python/aie_lit_utils/lit_config_helpers.py b/python/aie_lit_utils/lit_config_helpers.py index 00c4940542e..a48c88cd96f 100644 --- a/python/aie_lit_utils/lit_config_helpers.py +++ b/python/aie_lit_utils/lit_config_helpers.py @@ -88,7 +88,7 @@ def _prepend_env_paths(current_value: str, new_value: str) -> str: @staticmethod def _quote_lit_arg(value: str) -> str: """Quote arguments for lit's shell parser.""" - return "\"" + value.replace("\\", "/").replace("\"", "\\\"") + "\"" + return '"' + value.replace("\\", "/").replace('"', '\\"') + '"' @staticmethod def _run_on_npu_wrap(aie_src_root: str, npu_kind: str) -> str: @@ -123,7 +123,9 @@ def _find_xrt_smi(xrt_bin_dir: str) -> Optional[str]: if os.name == "nt": system_root = os.environ.get("SystemRoot", r"C:\Windows") - candidates.append(os.path.join(system_root, "System32", "AMD", "xrt-smi.exe")) + candidates.append( + os.path.join(system_root, "System32", "AMD", "xrt-smi.exe") + ) for candidate in candidates: if os.path.isfile(candidate): diff --git a/test/lit.cfg.py b/test/lit.cfg.py index 40a9b246e53..b9d2a6868b7 100644 --- a/test/lit.cfg.py +++ b/test/lit.cfg.py @@ -155,13 +155,17 @@ config.substitutions.append( ( "aiecc.py", - LitConfigHelper._quote_lit_arg(os.path.join(config.aie_tools_dir, "aiecc.py")), + LitConfigHelper._quote_lit_arg( + os.path.join(config.aie_tools_dir, "aiecc.py") + ), ) ) config.substitutions.append( ( "txn2mlir.py", - LitConfigHelper._quote_lit_arg(os.path.join(config.aie_tools_dir, "txn2mlir.py")), + LitConfigHelper._quote_lit_arg( + os.path.join(config.aie_tools_dir, "txn2mlir.py") + ), ) ) diff --git a/utils/run_on_npu.py b/utils/run_on_npu.py index 6559343aa73..7580523b672 100644 --- a/utils/run_on_npu.py +++ b/utils/run_on_npu.py @@ -6,6 +6,7 @@ import os import subprocess import sys +import tempfile def main() -> int: @@ -22,22 +23,30 @@ def main() -> int: completed = subprocess.run(command) return completed.returncode - xrt_dir = os.environ.get("XRT_DIR") or os.environ.get("XRT_ROOT") or "/opt/xilinx/xrt" + xrt_dir = ( + os.environ.get("XRT_DIR") or os.environ.get("XRT_ROOT") or "/opt/xilinx/xrt" + ) setup_script = os.path.join(xrt_dir, "setup.sh") if not os.path.isfile(setup_script): completed = subprocess.run(command) return completed.returncode + # Serialize Ryzen AI executions on POSIX runners to avoid contention. + import fcntl + + lock_path = os.path.join(tempfile.gettempdir(), "mlir_aie_run_on_npu.lock") bash_command = [ "bash", - "-lc", - 'source "$1" >/dev/null 2>&1; shift; exec "$@"', + "-c", + 'XRT_DIR="$1"; source "$XRT_DIR/setup.sh" >/dev/null 2>&1; shift; exec "$@"', "run_on_npu", - setup_script, + xrt_dir, *command, ] - completed = subprocess.run(bash_command) - return completed.returncode + with open(lock_path, "w") as lock_file: + fcntl.flock(lock_file.fileno(), fcntl.LOCK_EX) + completed = subprocess.run(bash_command) + return completed.returncode if __name__ == "__main__":