diff --git a/.bazelversion b/.bazelversion index 93c8dda..deeb3d6 100644 --- a/.bazelversion +++ b/.bazelversion @@ -1 +1 @@ -7.6.0 +9.2.0 diff --git a/.github/workflows/build-tests.yml b/.github/workflows/build-tests.yml index 9903569..6814338 100644 --- a/.github/workflows/build-tests.yml +++ b/.github/workflows/build-tests.yml @@ -50,6 +50,6 @@ jobs: run: | bazelisk --output_base="${{ matrix.legacy_output_base }}" build --noenable_bzlmod //tests/clim/... //tests/vila/... - name: Install vila python package - run: python -m pip install -e python[test] + run: python -m pip install -e .[test] - name: Test vila python package run: python -m pytest --cov=python/vila python/tests diff --git a/MODULE.bazel b/MODULE.bazel index f03b01d..7300b7c 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -17,17 +17,17 @@ limitations under the License. module(name = "vila", version = "1.0.6") bazel_dep(name = "bazel_skylib", version = "1.9.0") -bazel_dep(name = "bazel_features", version = "1.43.0") -bazel_dep(name = "rules_cc", version = "0.2.17") +bazel_dep(name = "bazel_features", version = "1.50.0") +bazel_dep(name = "rules_cc", version = "0.2.22") bazel_dep(name = "rules_python", version = "1.9.0") bazel_dep(name = "rules_shell", version = "0.8.0") bazel_dep(name = "rules_foreign_cc", version = "0.15.1") -bazel_dep(name = "googletest", version = "1.17.0", repo_name = "com_google_googletest") +bazel_dep(name = "googletest", version = "1.18.0", repo_name = "com_google_googletest") bazel_dep(name = "google_benchmark", version = "1.9.2", repo_name = "com_google_benchmark") bazel_dep(name = "pybind11_bazel", version = "3.0.0") bazel_dep(name = "nanobind_bazel", version = "2.10.2") bazel_dep(name = "fmt", version = "12.1.0") -bazel_dep(name = "platforms", version = "1.0.0") # python config depends platforms +bazel_dep(name = "platforms", version = "1.1.0") # python config depends platforms python = use_extension("@rules_python//python/extensions:python.bzl", "python") python.defaults(python_version = "3.12") @@ -59,16 +59,12 @@ use_repo(ittapi_ext, "ittapi") hedron_ext = use_extension("@vila//bazel/bzlmod:extensions.bzl", "hedron_extension") use_repo(hedron_ext, "hedron_compile_commands") -sycl_config_ext = use_extension("@vila//bazel/bzlmod:extensions.bzl", "sycl_configure_extension") -use_repo(sycl_config_ext, "local_config_sycl") +# SYCL is opt-in: consumers must configure and register the SYCL toolchain +# explicitly. To enable: +# sycl_config_ext = use_extension("@vila//bazel/bzlmod:extensions.bzl", "sycl_configure_extension") +# use_repo(sycl_config_ext, "local_config_sycl") +# register_toolchains("@local_config_sycl//:cc-toolchain-x64_sycl") # TVM FFI support (optional - requires: pip install apache-tvm-ffi) tvm_ffi_ext = use_extension("@vila//bazel/bzlmod:extensions.bzl", "tvm_ffi_extension") use_repo(tvm_ffi_ext, "tvm_ffi") - -register_toolchains( - # to use sycl specify: --config=sycl - "@local_config_sycl//:cc-toolchain-x64_sycl", - # Comment out the following line to use the bullseye on Windows - # "@local_config_bullseye//:cc-toolchain-x64_windows", -) diff --git a/bazel/bzlmod/extensions.bzl b/bazel/bzlmod/extensions.bzl index cc962bc..ad661b3 100644 --- a/bazel/bzlmod/extensions.bzl +++ b/bazel/bzlmod/extensions.bzl @@ -47,6 +47,7 @@ def load_rangev3(ctx): rangev3_version = "53c40dd628450c977ee1558285ff43e0613fa7a9" http_archive( name = "rangev3", + build_file = "@vila//bazel:rangev3.BUILD", integrity = "sha256-3uvT1HqOcMb2maFCPul05Ku/AWqCAZEdYFQe4eRWFFQ=", strip_prefix = "range-v3-%s" % rangev3_version, url = "https://github.com/ericniebler/range-v3/archive/%s.zip" % rangev3_version, diff --git a/bazel/hlsl/hlsl_configure.bzl b/bazel/hlsl/hlsl_configure.bzl index a90477f..cd211fa 100644 --- a/bazel/hlsl/hlsl_configure.bzl +++ b/bazel/hlsl/hlsl_configure.bzl @@ -6,7 +6,7 @@ E-mail: wenyitang@outlook.com Configure HLSL compilers """ -load("@bazel_tools//tools/cpp:windows_cc_configure.bzl", "find_vc_path", "setup_vc_env_vars") +load("@rules_cc//cc/private/toolchain:windows_cc_configure.bzl", "find_vc_path", "setup_vc_env_vars") def _hlsl_configure(ctx): vc_path = find_vc_path(ctx) diff --git a/bazel/ittapi.BUILD b/bazel/ittapi.BUILD index 8fd06bd..984fcf6 100644 --- a/bazel/ittapi.BUILD +++ b/bazel/ittapi.BUILD @@ -16,7 +16,9 @@ cc_library( ]), hdrs = [ "include/ittnotify.h", + "include/ittnotify-zca.h", "include/jitprofiling.h", + "include/legacy/ittnotify.h", "include/libittnotify.h", ], defines = ["VILA_ITT_ENABLED=1"], diff --git a/bazel/pre_compile.bzl b/bazel/pre_compile.bzl index e06cd49..629705e 100644 --- a/bazel/pre_compile.bzl +++ b/bazel/pre_compile.bzl @@ -48,6 +48,8 @@ Ref: 3. https://learn.microsoft.com/en-us/cpp/build/reference/yu-use-precompiled-header-file """ +load("@rules_cc//cc:defs.bzl", "cc_library") + def _make_pch_impl(ctx): ctx.actions.write( output = ctx.outputs.pch_cxx, @@ -88,11 +90,11 @@ def pch_library(name, pch_hdr, deps = [], cc_library_cb = None): ) pch_lbl = Label(pch_hdr) pch_path = "$(BINDIR)/" + pch_lbl.package.replace("/", "_") + "_" + pch_lbl.name + ".pch" - cc_library = native.cc_library if cc_library_cb == None else cc_library_cb - cc_library( + cc_library_rule = cc_library if cc_library_cb == None else cc_library_cb + cc_library_rule( name = name, srcs = [":" + name + "_pch"], - hdrs = [pch_header], + hdrs = [pch_header, pch_hdr], copts = [ "/Yc" + pch_header, "/FI" + pch_header, diff --git a/bazel/rangev3.BUILD b/bazel/rangev3.BUILD new file mode 100644 index 0000000..2f8c0f4 --- /dev/null +++ b/bazel/rangev3.BUILD @@ -0,0 +1,45 @@ +package(default_visibility = ["//visibility:public"]) + +load("@rules_cc//cc:defs.bzl", "cc_library") + +cc_library( + name = "concepts", + hdrs = glob([ + "include/concepts/**/*.hpp", + ]), + includes = [ + "include", + ], +) + +cc_library( + name = "meta", + hdrs = glob([ + "include/meta/**/*.hpp", + ]), + includes = [ + "include", + ], +) + +cc_library( + name = "std", + hdrs = glob([ + "include/std/**/*.hpp", + ]), + includes = [ + "include", + ], +) + +cc_library( + name = "range-v3", + hdrs = glob([ + "include/range/v3/**/*.hpp", + ]), + deps = [ + ":concepts", + ":meta", + ":std", + ], +) diff --git a/bazel/toolchains/BUILD_bullseye.tpl b/bazel/toolchains/BUILD_bullseye.tpl index 70b64bf..881d534 100644 --- a/bazel/toolchains/BUILD_bullseye.tpl +++ b/bazel/toolchains/BUILD_bullseye.tpl @@ -6,7 +6,8 @@ E-mail: wenyitang@outlook.com custom cc toolchains for Windows """ -load("@bazel_tools//tools/cpp:windows_cc_toolchain_config.bzl", "cc_toolchain_config") +load("@rules_cc//cc/private/toolchain:windows_cc_toolchain_config.bzl", "cc_toolchain_config") +load("@rules_cc//cc:defs.bzl", "cc_toolchain", "cc_toolchain_suite") package(default_visibility = ["//visibility:public"]) diff --git a/bazel/toolchains/BUILD_sycl.tpl b/bazel/toolchains/BUILD_sycl.tpl index f784862..430650c 100644 --- a/bazel/toolchains/BUILD_sycl.tpl +++ b/bazel/toolchains/BUILD_sycl.tpl @@ -7,6 +7,7 @@ custom cc toolchains for Windows """ load("@vila//bazel/toolchains:sycl_cc_toolchain_config.bzl", "cc_toolchain_config") +load("@rules_cc//cc:defs.bzl", "cc_toolchain", "cc_toolchain_suite") package(default_visibility = ["//visibility:public"]) diff --git a/bazel/toolchains/BUILD_sycl_unix.tpl b/bazel/toolchains/BUILD_sycl_unix.tpl index c9d69be..8d55ff6 100644 --- a/bazel/toolchains/BUILD_sycl_unix.tpl +++ b/bazel/toolchains/BUILD_sycl_unix.tpl @@ -15,7 +15,7 @@ # This becomes the BUILD file for @local_config_cc// under non-BSD unixes. load(":cc_toolchain_config.bzl", "cc_toolchain_config") -load("@rules_cc//cc:defs.bzl", "cc_toolchain", "cc_toolchain_suite") +load("@rules_cc//cc:defs.bzl", "cc_library", "cc_toolchain", "cc_toolchain_suite") package(default_visibility = ["//visibility:public"]) diff --git a/bazel/toolchains/bullseye_cc_configure.bzl b/bazel/toolchains/bullseye_cc_configure.bzl index 5bf1945..6ec5258 100644 --- a/bazel/toolchains/bullseye_cc_configure.bzl +++ b/bazel/toolchains/bullseye_cc_configure.bzl @@ -87,9 +87,9 @@ def _resolve_labels(repository_ctx, labels): def _bullseye_configure(repository_ctx): paths = _resolve_labels(repository_ctx, [ "@vila//bazel/toolchains:BUILD_bullseye.tpl", - "@bazel_tools//tools/cpp:windows_cc_toolchain_config.bzl", - "@bazel_tools//tools/cpp:vc_installation_error.bat.tpl", - "@bazel_tools//tools/cpp:clang_installation_error.bat.tpl", + "@rules_cc//cc/private/toolchain:windows_cc_toolchain_config.bzl", + "@rules_cc//cc/private/toolchain:vc_installation_error.bat.tpl", + "@rules_cc//cc/private/toolchain:clang_installation_error.bat.tpl", ]) if is_windows(repository_ctx): diff --git a/bazel/toolchains/sycl_cc_configure.bzl b/bazel/toolchains/sycl_cc_configure.bzl index 2d25999..0f43261 100644 --- a/bazel/toolchains/sycl_cc_configure.bzl +++ b/bazel/toolchains/sycl_cc_configure.bzl @@ -151,15 +151,15 @@ def _sycl_configure(repository_ctx): "@vila//bazel/toolchains:BUILD_sycl.tpl", "@vila//bazel/toolchains:BUILD_sycl_unix.tpl", # required by msvc - "@bazel_tools//tools/cpp:windows_cc_toolchain_config.bzl", - "@bazel_tools//tools/cpp:vc_installation_error.bat.tpl", - "@bazel_tools//tools/cpp:clang_installation_error.bat.tpl", + "@rules_cc//cc/private/toolchain:windows_cc_toolchain_config.bzl", + "@rules_cc//cc/private/toolchain:vc_installation_error.bat.tpl", + "@rules_cc//cc/private/toolchain:clang_installation_error.bat.tpl", # required by unix - "@bazel_tools//tools/cpp:generate_system_module_map.sh", - "@bazel_tools//tools/cpp:armeabi_cc_toolchain_config.bzl", - "@bazel_tools//tools/cpp:unix_cc_toolchain_config.bzl", - "@bazel_tools//tools/cpp:linux_cc_wrapper.sh.tpl", - "@bazel_tools//tools/cpp:osx_cc_wrapper.sh.tpl", + "@rules_cc//cc/private/toolchain:generate_system_module_map.sh", + "@rules_cc//cc/private/toolchain:armeabi_cc_toolchain_config.bzl", + "@rules_cc//cc/private/toolchain:unix_cc_toolchain_config.bzl", + "@rules_cc//cc/private/toolchain:linux_cc_wrapper.sh.tpl", + "@rules_cc//cc/private/toolchain:osx_cc_wrapper.sh.tpl", ]) repo_name = repository_ctx.name.split("~")[-1] diff --git a/bazel/toolchains/sycl_cc_toolchain_config.bzl b/bazel/toolchains/sycl_cc_toolchain_config.bzl index 38f4e28..3cc73ac 100644 --- a/bazel/toolchains/sycl_cc_toolchain_config.bzl +++ b/bazel/toolchains/sycl_cc_toolchain_config.bzl @@ -19,7 +19,7 @@ A Starlark cc_toolchain configuration rule for Windows. load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "ACTION_NAMES") load( - "@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl", + "@rules_cc//cc:cc_toolchain_config_lib.bzl", "action_config", "artifact_name_pattern", "env_entry", @@ -32,6 +32,7 @@ load( "variable_with_value", "with_feature_set", ) +load("@rules_cc//cc/toolchains:cc_toolchain_config_info.bzl", "CcToolchainConfigInfo") load("@rules_cc//cc/common:cc_common.bzl", "cc_common") all_compile_actions = [ diff --git a/bazel/toolchains/unix_toolchain_configure.bzl b/bazel/toolchains/unix_toolchain_configure.bzl index 1b97477..9e4b52d 100644 --- a/bazel/toolchains/unix_toolchain_configure.bzl +++ b/bazel/toolchains/unix_toolchain_configure.bzl @@ -15,7 +15,7 @@ """Configuring the C++ toolchain on Unix platforms.""" load( - "@bazel_tools//tools/cpp:lib_cc_configure.bzl", + "@rules_cc//cc/private/toolchain:lib_cc_configure.bzl", "auto_configure_fail", "auto_configure_warning", "auto_configure_warning_maybe", @@ -314,12 +314,12 @@ def find_cc(repository_ctx, overriden_tools): def configure_unix_toolchain(repository_ctx, paths, cpu_value, overriden_tools): """Configure C++ toolchain on Unix platforms.""" repository_ctx.symlink( - paths["@bazel_tools//tools/cpp:unix_cc_toolchain_config.bzl"], + paths["@rules_cc//cc/private/toolchain:unix_cc_toolchain_config.bzl"], "cc_toolchain_config.bzl", ) repository_ctx.symlink( - paths["@bazel_tools//tools/cpp:armeabi_cc_toolchain_config.bzl"], + paths["@rules_cc//cc/private/toolchain:armeabi_cc_toolchain_config.bzl"], "armeabi_cc_toolchain_config.bzl", ) @@ -380,7 +380,7 @@ def configure_unix_toolchain(repository_ctx, paths, cpu_value, overriden_tools): )) cc_wrapper_src = ( - "@bazel_tools//tools/cpp:osx_cc_wrapper.sh.tpl" if darwin else "@bazel_tools//tools/cpp:linux_cc_wrapper.sh.tpl" + "@rules_cc//cc/private/toolchain:osx_cc_wrapper.sh.tpl" if darwin else "@rules_cc//cc/private/toolchain:linux_cc_wrapper.sh.tpl" ) repository_ctx.template( "cc_wrapper.sh", @@ -524,7 +524,7 @@ def configure_unix_toolchain(repository_ctx, paths, cpu_value, overriden_tools): repository_ctx.file("module.modulemap", _generate_system_module_map( repository_ctx, builtin_include_directories, - paths["@bazel_tools//tools/cpp:generate_system_module_map.sh"], + paths["@rules_cc//cc/private/toolchain:generate_system_module_map.sh"], )) extra_flags_per_feature = {} if is_clang: diff --git a/bazel/toolchains/windows_toolchain_configure.bzl b/bazel/toolchains/windows_toolchain_configure.bzl index 2262952..a8ee443 100644 --- a/bazel/toolchains/windows_toolchain_configure.bzl +++ b/bazel/toolchains/windows_toolchain_configure.bzl @@ -6,7 +6,7 @@ E-mail: wenyi.tang@intel.com """ load( - "@bazel_tools//tools/cpp:lib_cc_configure.bzl", + "@rules_cc//cc/private/toolchain:lib_cc_configure.bzl", "auto_configure_fail", "auto_configure_warning", "auto_configure_warning_maybe", @@ -15,7 +15,7 @@ load( "write_builtin_include_directory_paths", ) load( - "@bazel_tools//tools/cpp:windows_cc_configure.bzl", + "@rules_cc//cc/private/toolchain:windows_cc_configure.bzl", "find_llvm_path", "find_llvm_tool", "find_msvc_tool", @@ -244,7 +244,7 @@ def get_msvc_vars(repository_ctx, paths, target_arch = "x64", msvc_vars_x64 = No if not vc_path: repository_ctx.template( "vc_installation_error_" + target_arch + ".bat", - paths["@bazel_tools//tools/cpp:vc_installation_error.bat.tpl"], + paths["@rules_cc//cc/private/toolchain:vc_installation_error.bat.tpl"], {"%{vc_error_message}": ""}, ) else: @@ -260,7 +260,7 @@ def get_msvc_vars(repository_ctx, paths, target_arch = "x64", msvc_vars_x64 = No ]) repository_ctx.template( "vc_installation_error_" + target_arch + ".bat", - paths["@bazel_tools//tools/cpp:vc_installation_error.bat.tpl"], + paths["@rules_cc//cc/private/toolchain:vc_installation_error.bat.tpl"], {"%{vc_error_message}": message}, ) @@ -356,7 +356,7 @@ def get_clang_cl_vars(repository_ctx, paths, msvc_vars, target_arch): elif not llvm_path: repository_ctx.template( "clang_installation_error.bat", - paths["@bazel_tools//tools/cpp:clang_installation_error.bat.tpl"], + paths["@rules_cc//cc/private/toolchain:clang_installation_error.bat.tpl"], {"%{clang_error_message}": ""}, ) error_script = "clang_installation_error.bat" @@ -372,7 +372,7 @@ def get_clang_cl_vars(repository_ctx, paths, msvc_vars, target_arch): ]) repository_ctx.template( "clang_installation_error.bat", - paths["@bazel_tools//tools/cpp:clang_installation_error.bat.tpl"], + paths["@rules_cc//cc/private/toolchain:clang_installation_error.bat.tpl"], {"%{clang_error_message}": message}, ) error_script = "clang_installation_error.bat" diff --git a/bazel/tvm_ffi_configure.bzl b/bazel/tvm_ffi_configure.bzl index effa34d..023aead 100644 --- a/bazel/tvm_ffi_configure.bzl +++ b/bazel/tvm_ffi_configure.bzl @@ -28,6 +28,46 @@ Example in WORKSPACE: tvm_ffi_configure(name = "tvm_ffi") """ +def _lookup_env_var(env, name, default = None): + for key, value in env.items(): + if name.lower() == key.lower(): + return value + return default + +def _find_python(repository_ctx): + """Locate a usable Python interpreter. + + Bazel 8's repository_ctx.which() rejects the 0-byte "app execution alias" + stubs (python.exe/python3.exe) that Microsoft places on PATH, so fall back + to the real interpreter install under %LOCALAPPDATA%\\Python. + """ + if repository_ctx.attr.python: + p = repository_ctx.path(repository_ctx.attr.python) + if p.exists: + return p + + for name in ["python3", "python"]: + p = repository_ctx.which(name) + if p and p.exists: + return p + + if repository_ctx.os.name.lower().startswith("windows"): + localappdata = _lookup_env_var(repository_ctx.os.environ, "LOCALAPPDATA") + if localappdata: + python_dir = repository_ctx.path(localappdata).get_child("Python") + if python_dir.exists: + # Prefer newest version directory, mirroring install layout: + # \\Python\\pythoncore-\\python.exe + versions = sorted( + [d for d in python_dir.readdir() if d.get_child("python.exe").exists], + key = lambda d: d.basename, + reverse = True, + ) + if versions: + return versions[0].get_child("python.exe") + + return None + def _tvm_ffi_configure(repository_ctx): """Repository rule implementation to locate TVM FFI from pip installation. @@ -47,13 +87,10 @@ def _tvm_ffi_configure(repository_ctx): """ # Step 1: Find Python executable - # This is the Python that rules_python registers via python_register_toolchains - python_path = repository_ctx.which("python3") - if not python_path: - python_path = repository_ctx.which("python") + python_path = _find_python(repository_ctx) # Verify Python was found - if not python_path or not python_path.exists: + if not python_path: fail( "Python not found. Please either:\n" + "1. Install apache-tvm-ffi: pip install apache-tvm-ffi\n" + @@ -172,6 +209,10 @@ load("@rules_cc//cc:defs.bzl", "cc_import", "cc_library") {imports} cc_library( name = "tvm_ffi", + hdrs = glob([ + "include/**", + "dlpack/**", + ]), includes = [ "include", "dlpack", @@ -191,4 +232,9 @@ cc_library( # Define the repository rule for Bazel # Repository rules are used to fetch and configure external dependencies. # This rule is called once per Bazel invocation to set up the TVM FFI dependency. -tvm_ffi_configure = repository_rule(implementation = _tvm_ffi_configure) +tvm_ffi_configure = repository_rule( + implementation = _tvm_ffi_configure, + attrs = { + "python": attr.string(doc = "Explicit path to the Python interpreter. If unset, auto-discovered."), + }, +) diff --git a/bazel/wdk/wdk_configure.bzl b/bazel/wdk/wdk_configure.bzl index 1c36398..eb70237 100644 --- a/bazel/wdk/wdk_configure.bzl +++ b/bazel/wdk/wdk_configure.bzl @@ -6,7 +6,7 @@ E-mail: wenyitang@outlook.com Locate Windows Driver Kit (WDK) """ -load("@bazel_tools//tools/cpp:windows_cc_configure.bzl", "find_vc_path", "setup_vc_env_vars") +load("@rules_cc//cc/private/toolchain:windows_cc_configure.bzl", "find_vc_path", "setup_vc_env_vars") def _wdk_configure(ctx): vc_path = find_vc_path(ctx) diff --git a/tests/vila/hook/BUILD.bazel b/tests/vila/hook/BUILD.bazel index a644edf..9eda57e 100644 --- a/tests/vila/hook/BUILD.bazel +++ b/tests/vila/hook/BUILD.bazel @@ -19,7 +19,10 @@ load("@rules_cc//cc:cc_import.bzl", "cc_import") cc_binary( name = "dll_to_hook", - srcs = ["dll_to_hook.cc"], + srcs = [ + "dll_to_hook.cc", + "dll_to_hook.h", + ], defines = ["DLL_EXPORT"], includes = ["."], linkopts = [ diff --git a/vila/hook/detours/BUILD.bazel b/vila/hook/detours/BUILD.bazel index 59538e6..bf53377 100644 --- a/vila/hook/detours/BUILD.bazel +++ b/vila/hook/detours/BUILD.bazel @@ -16,12 +16,38 @@ limitations under the License. load("@rules_cc//cc:cc_library.bzl", "cc_library") +# disasm.cpp is both compiled standalone (provides the host-arch +# DetourCopyInstruction used by detours.cpp) and #included by the disol*.cpp +# files (which redefine it as DetourCopyInstructionX86/X64/... via the +# DETOURS_*_OFFLINE_LIBRARY macros). Bazel 9 requires an #included .cpp to be +# listed in textual_hdrs, so it cannot also live in srcs of the same rule; +# compile it in its own library and depend on it. +cc_library( + name = "disasm", + srcs = ["disasm.cpp"], + hdrs = [ + "detours.h", + "detver.h", + ], + copts = [ + "/W4", + "/Z7", + "/Gy", + "/Gm-", + "/Zl", + "/Od", + "/FS", + ], + includes = ["."], + target_compatible_with = ["@platforms//os:windows"], + visibility = ["//visibility:private"], +) + cc_library( name = "detours", srcs = [ "creatwth.cpp", "detours.cpp", - "disasm.cpp", "disolarm.cpp", "disolarm64.cpp", "disolia64.cpp", @@ -49,6 +75,10 @@ cc_library( ], includes = ["."], target_compatible_with = ["@platforms//os:windows"], - textual_hdrs = ["uimports.cpp"], + textual_hdrs = [ + "disasm.cpp", + "uimports.cpp", + ], visibility = ["//visibility:public"], + deps = [":disasm"], )