| # -*- Python -*- |
| |
| # Configuration file for the 'lit' test runner. |
| |
| import os |
| import sys |
| import re |
| import platform |
| import subprocess |
| |
| import lit.util |
| import lit.formats |
| from lit.llvm import llvm_config |
| from lit.llvm.subst import FindTool |
| from lit.llvm.subst import ToolSubst |
| |
| # name: The name of this test suite. |
| config.name = "LLVM" |
| |
| # testFormat: The test format to use to interpret tests. |
| config.test_format = lit.formats.ShTest(not llvm_config.use_lit_shell) |
| |
| # suffixes: A list of file extensions to treat as test files. This is overriden |
| # by individual lit.local.cfg files in the test subdirectories. |
| config.suffixes = [".ll", ".c", ".test", ".txt", ".s", ".mir", ".yaml"] |
| |
| # excludes: A list of directories to exclude from the testsuite. The 'Inputs' |
| # subdirectories contain auxiliary inputs for various tests in their parent |
| # directories. |
| config.excludes = ["Inputs", "CMakeLists.txt", "README.txt", "LICENSE.txt"] |
| |
| # test_source_root: The root path where tests are located. |
| config.test_source_root = os.path.dirname(__file__) |
| |
| # test_exec_root: The root path where tests should be run. |
| config.test_exec_root = os.path.join(config.llvm_obj_root, "test") |
| |
| # Tweak the PATH to include the tools dir. |
| llvm_config.with_environment("PATH", config.llvm_tools_dir, append_path=True) |
| |
| # Propagate some variables from the host environment. |
| llvm_config.with_system_environment(["HOME", "INCLUDE", "LIB", "TMP", "TEMP"]) |
| |
| |
| # Set up OCAMLPATH to include newly built OCaml libraries. |
| top_ocaml_lib = os.path.join(config.llvm_lib_dir, "ocaml") |
| llvm_ocaml_lib = os.path.join(top_ocaml_lib, "llvm") |
| |
| llvm_config.with_system_environment("OCAMLPATH") |
| llvm_config.with_environment("OCAMLPATH", top_ocaml_lib, append_path=True) |
| llvm_config.with_environment("OCAMLPATH", llvm_ocaml_lib, append_path=True) |
| |
| llvm_config.with_system_environment("CAML_LD_LIBRARY_PATH") |
| llvm_config.with_environment("CAML_LD_LIBRARY_PATH", llvm_ocaml_lib, append_path=True) |
| |
| # Set up OCAMLRUNPARAM to enable backtraces in OCaml tests. |
| llvm_config.with_environment("OCAMLRUNPARAM", "b") |
| |
| # Provide the path to asan runtime lib 'libclang_rt.asan_osx_dynamic.dylib' if |
| # available. This is darwin specific since it's currently only needed on darwin. |
| |
| |
| def get_asan_rtlib(): |
| if ( |
| not "Address" in config.llvm_use_sanitizer |
| or not "Darwin" in config.host_os |
| or not "x86" in config.host_triple |
| ): |
| return "" |
| try: |
| import glob |
| except: |
| print("glob module not found, skipping get_asan_rtlib() lookup") |
| return "" |
| # The libclang_rt.asan_osx_dynamic.dylib path is obtained using the relative |
| # path from the host cc. |
| host_lib_dir = os.path.join(os.path.dirname(config.host_cc), "../lib") |
| asan_dylib_dir_pattern = ( |
| host_lib_dir + "/clang/*/lib/darwin/libclang_rt.asan_osx_dynamic.dylib" |
| ) |
| found_dylibs = glob.glob(asan_dylib_dir_pattern) |
| if len(found_dylibs) != 1: |
| return "" |
| return found_dylibs[0] |
| |
| |
| llvm_config.use_default_substitutions() |
| |
| # Add site-specific substitutions. |
| config.substitutions.append(("%llvmshlibdir", config.llvm_shlib_dir)) |
| config.substitutions.append(("%shlibext", config.llvm_shlib_ext)) |
| config.substitutions.append(("%pluginext", config.llvm_plugin_ext)) |
| config.substitutions.append(("%exeext", config.llvm_exe_ext)) |
| |
| |
| lli_args = [] |
| # The target triple used by default by lli is the process target triple (some |
| # triple appropriate for generating code for the current process) but because |
| # we don't support COFF in MCJIT well enough for the tests, force ELF format on |
| # Windows. FIXME: the process target triple should be used here, but this is |
| # difficult to obtain on Windows. |
| if re.search(r"cygwin|windows-gnu|windows-msvc", config.host_triple): |
| lli_args = ["-mtriple=" + config.host_triple + "-elf"] |
| |
| llc_args = [] |
| |
| # Similarly, have a macro to use llc with DWARF even when the host is Windows |
| if re.search(r"windows-msvc", config.target_triple): |
| llc_args = [" -mtriple=" + config.target_triple.replace("-msvc", "-gnu")] |
| |
| # Provide the path to asan runtime lib if available. On darwin, this lib needs |
| # to be loaded via DYLD_INSERT_LIBRARIES before libLTO.dylib in case the files |
| # to be linked contain instrumented sanitizer code. |
| ld64_cmd = config.ld64_executable |
| asan_rtlib = get_asan_rtlib() |
| if asan_rtlib: |
| ld64_cmd = "DYLD_INSERT_LIBRARIES={} {}".format(asan_rtlib, ld64_cmd) |
| if config.osx_sysroot: |
| ld64_cmd = "{} -syslibroot {}".format(ld64_cmd, config.osx_sysroot) |
| |
| ocamlc_command = "%s ocamlc -cclib -L%s %s" % ( |
| config.ocamlfind_executable, |
| config.llvm_lib_dir, |
| config.ocaml_flags, |
| ) |
| ocamlopt_command = "true" |
| if config.have_ocamlopt: |
| ocamlopt_command = "%s ocamlopt -cclib -L%s -cclib -Wl,-rpath,%s %s" % ( |
| config.ocamlfind_executable, |
| config.llvm_lib_dir, |
| config.llvm_lib_dir, |
| config.ocaml_flags, |
| ) |
| |
| opt_viewer_cmd = "%s %s/tools/opt-viewer/opt-viewer.py" % ( |
| sys.executable, |
| config.llvm_src_root, |
| ) |
| |
| llvm_original_di_preservation_cmd = os.path.join( |
| config.llvm_src_root, "utils", "llvm-original-di-preservation.py" |
| ) |
| config.substitutions.append( |
| ( |
| "%llvm-original-di-preservation", |
| "'%s' %s" % (config.python_executable, llvm_original_di_preservation_cmd), |
| ) |
| ) |
| |
| llvm_locstats_tool = os.path.join(config.llvm_tools_dir, "llvm-locstats") |
| config.substitutions.append( |
| ("%llvm-locstats", "'%s' %s" % (config.python_executable, llvm_locstats_tool)) |
| ) |
| config.llvm_locstats_used = os.path.exists(llvm_locstats_tool) |
| |
| tools = [ |
| ToolSubst("%llvm", FindTool("llvm"), unresolved="ignore"), |
| ToolSubst("%lli", FindTool("lli"), post=".", extra_args=lli_args), |
| ToolSubst("%llc_dwarf", FindTool("llc"), extra_args=llc_args), |
| ToolSubst("%gold", config.gold_executable, unresolved="ignore"), |
| ToolSubst("%ld64", ld64_cmd, unresolved="ignore"), |
| ToolSubst("%ocamlc", ocamlc_command, unresolved="ignore"), |
| ToolSubst("%ocamlopt", ocamlopt_command, unresolved="ignore"), |
| ToolSubst("%opt-viewer", opt_viewer_cmd), |
| ToolSubst("%llvm-objcopy", FindTool("llvm-objcopy")), |
| ToolSubst("%llvm-strip", FindTool("llvm-strip")), |
| ToolSubst("%llvm-install-name-tool", FindTool("llvm-install-name-tool")), |
| ToolSubst("%llvm-bitcode-strip", FindTool("llvm-bitcode-strip")), |
| ToolSubst("%split-file", FindTool("split-file")), |
| ] |
| |
| # FIXME: Why do we have both `lli` and `%lli` that do slightly different things? |
| tools.extend( |
| [ |
| "dsymutil", |
| "lli", |
| "lli-child-target", |
| "llvm-ar", |
| "llvm-as", |
| "llvm-addr2line", |
| "llvm-bcanalyzer", |
| "llvm-bitcode-strip", |
| "llvm-config", |
| "llvm-cov", |
| "llvm-cxxdump", |
| "llvm-cvtres", |
| "llvm-debuginfod-find", |
| "llvm-debuginfo-analyzer", |
| "llvm-diff", |
| "llvm-dis", |
| "llvm-dwarfdump", |
| "llvm-dwarfutil", |
| "llvm-dwp", |
| "llvm-dlltool", |
| "llvm-exegesis", |
| "llvm-extract", |
| "llvm-isel-fuzzer", |
| "llvm-ifs", |
| "llvm-install-name-tool", |
| "llvm-jitlink", |
| "llvm-opt-fuzzer", |
| "llvm-lib", |
| "llvm-link", |
| "llvm-lto", |
| "llvm-lto2", |
| "llvm-mc", |
| "llvm-mca", |
| "llvm-modextract", |
| "llvm-nm", |
| "llvm-objcopy", |
| "llvm-objdump", |
| "llvm-otool", |
| "llvm-pdbutil", |
| "llvm-profdata", |
| "llvm-profgen", |
| "llvm-ranlib", |
| "llvm-rc", |
| "llvm-readelf", |
| "llvm-readobj", |
| "llvm-rtdyld", |
| "llvm-sim", |
| "llvm-size", |
| "llvm-split", |
| "llvm-stress", |
| "llvm-strings", |
| "llvm-strip", |
| "llvm-tblgen", |
| "llvm-readtapi", |
| "llvm-undname", |
| "llvm-windres", |
| "llvm-c-test", |
| "llvm-cxxfilt", |
| "llvm-xray", |
| "yaml2obj", |
| "obj2yaml", |
| "yaml-bench", |
| "verify-uselistorder", |
| "bugpoint", |
| "llc", |
| "llvm-symbolizer", |
| "opt", |
| "sancov", |
| "sanstats", |
| "llvm-remarkutil", |
| ] |
| ) |
| |
| # The following tools are optional |
| tools.extend( |
| [ |
| ToolSubst("llvm-mt", unresolved="ignore"), |
| ToolSubst("llvm-debuginfod", unresolved="ignore"), |
| ToolSubst("Kaleidoscope-Ch3", unresolved="ignore"), |
| ToolSubst("Kaleidoscope-Ch4", unresolved="ignore"), |
| ToolSubst("Kaleidoscope-Ch5", unresolved="ignore"), |
| ToolSubst("Kaleidoscope-Ch6", unresolved="ignore"), |
| ToolSubst("Kaleidoscope-Ch7", unresolved="ignore"), |
| ToolSubst("Kaleidoscope-Ch8", unresolved="ignore"), |
| ToolSubst("LLJITWithThinLTOSummaries", unresolved="ignore"), |
| ToolSubst("LLJITWithRemoteDebugging", unresolved="ignore"), |
| ToolSubst("OrcV2CBindingsBasicUsage", unresolved="ignore"), |
| ToolSubst("OrcV2CBindingsAddObjectFile", unresolved="ignore"), |
| ToolSubst("OrcV2CBindingsRemovableCode", unresolved="ignore"), |
| ToolSubst("OrcV2CBindingsLazy", unresolved="ignore"), |
| ToolSubst("OrcV2CBindingsVeryLazy", unresolved="ignore"), |
| ToolSubst("dxil-dis", unresolved="ignore"), |
| ] |
| ) |
| |
| # Find (major, minor) version of ptxas |
| def ptxas_version(ptxas): |
| ptxas_cmd = subprocess.Popen([ptxas, "--version"], stdout=subprocess.PIPE) |
| ptxas_out = ptxas_cmd.stdout.read().decode("ascii") |
| ptxas_cmd.wait() |
| match = re.search(r"release (\d+)\.(\d+)", ptxas_out) |
| if match: |
| return (int(match.group(1)), int(match.group(2))) |
| print("couldn't determine ptxas version") |
| return None |
| |
| |
| # Enable %ptxas and %ptxas-verify tools. |
| # %ptxas-verify defaults to sm_60 architecture. It can be overriden |
| # by specifying required one, for instance: %ptxas-verify -arch=sm_80. |
| def enable_ptxas(ptxas_executable): |
| version = ptxas_version(ptxas_executable) |
| if version: |
| # ptxas is supposed to be backward compatible with previous |
| # versions, so add a feature for every known version prior to |
| # the current one. |
| ptxas_known_versions = [ |
| (9, 0), |
| (9, 1), |
| (9, 2), |
| (10, 0), |
| (10, 1), |
| (10, 2), |
| (11, 0), |
| (11, 1), |
| (11, 2), |
| (11, 3), |
| (11, 4), |
| (11, 5), |
| (11, 6), |
| (11, 7), |
| (11, 8), |
| (12, 0), |
| (12, 1), |
| (12, 2), |
| (12, 3), |
| (12, 4), |
| ] |
| |
| def version_int(ver): |
| return ver[0] * 100 + ver[1] |
| |
| # ignore ptxas if its version is below the minimum supported |
| # version |
| min_version = ptxas_known_versions[0] |
| if version_int(version) < version_int(min_version): |
| print( |
| "Warning: ptxas version {}.{} is not supported".format( |
| version[0], version[1] |
| ) |
| ) |
| return |
| |
| for known_version in ptxas_known_versions: |
| if version_int(known_version) <= version_int(version): |
| major, minor = known_version |
| config.available_features.add("ptxas-{}.{}".format(major, minor)) |
| |
| config.available_features.add("ptxas") |
| tools.extend( |
| [ |
| ToolSubst("%ptxas", ptxas_executable), |
| ToolSubst("%ptxas-verify", "{} -arch=sm_60 -c -".format(ptxas_executable)), |
| ] |
| ) |
| |
| |
| ptxas_executable = ( |
| os.environ.get("LLVM_PTXAS_EXECUTABLE", None) or config.ptxas_executable |
| ) |
| if ptxas_executable: |
| enable_ptxas(ptxas_executable) |
| |
| llvm_config.add_tool_substitutions(tools, config.llvm_tools_dir) |
| |
| # Targets |
| |
| config.targets = frozenset(config.targets_to_build.split()) |
| |
| for arch in config.targets_to_build.split(): |
| config.available_features.add(arch.lower() + "-registered-target") |
| |
| # Features |
| known_arches = ["x86_64", "mips64", "ppc64", "aarch64"] |
| if config.host_ldflags.find("-m32") < 0 and any( |
| config.llvm_host_triple.startswith(x) for x in known_arches |
| ): |
| config.available_features.add("llvm-64-bits") |
| |
| config.available_features.add("host-byteorder-" + sys.byteorder + "-endian") |
| |
| if sys.platform in ["win32"]: |
| # ExecutionEngine, no weak symbols in COFF. |
| config.available_features.add("uses_COFF") |
| else: |
| # Others/can-execute.txt |
| config.available_features.add("can-execute") |
| |
| # Loadable module |
| if config.has_plugins: |
| config.available_features.add("plugins") |
| |
| if config.build_examples: |
| config.available_features.add("examples") |
| |
| if config.linked_bye_extension: |
| config.substitutions.append(("%llvmcheckext", "CHECK-EXT")) |
| config.substitutions.append(("%loadbye", "")) |
| config.substitutions.append(("%loadnewpmbye", "")) |
| else: |
| config.substitutions.append(("%llvmcheckext", "CHECK-NOEXT")) |
| config.substitutions.append( |
| ( |
| "%loadbye", |
| "-load={}/Bye{}".format(config.llvm_shlib_dir, config.llvm_shlib_ext), |
| ) |
| ) |
| config.substitutions.append( |
| ( |
| "%loadnewpmbye", |
| "-load-pass-plugin={}/Bye{}".format( |
| config.llvm_shlib_dir, config.llvm_shlib_ext |
| ), |
| ) |
| ) |
| |
| if config.linked_exampleirtransforms_extension: |
| config.substitutions.append(("%loadexampleirtransforms", "")) |
| else: |
| config.substitutions.append( |
| ( |
| "%loadexampleirtransforms", |
| "-load-pass-plugin={}/ExampleIRTransforms{}".format( |
| config.llvm_shlib_dir, config.llvm_shlib_ext |
| ), |
| ) |
| ) |
| |
| # Static libraries are not built if BUILD_SHARED_LIBS is ON. |
| if not config.build_shared_libs and not config.link_llvm_dylib: |
| config.available_features.add("static-libs") |
| |
| if config.link_llvm_dylib: |
| config.available_features.add("llvm-dylib") |
| config.substitutions.append( |
| ( |
| # libLLVM.so.19.0git |
| "%llvmdylib", |
| "{}/libLLVM{}.{}".format( |
| config.llvm_shlib_dir, config.llvm_shlib_ext, config.llvm_dylib_version |
| ) |
| ) |
| ) |
| |
| if config.have_tf_aot: |
| config.available_features.add("have_tf_aot") |
| |
| if config.have_tflite: |
| config.available_features.add("have_tflite") |
| |
| if config.llvm_inliner_model_autogenerated: |
| config.available_features.add("llvm_inliner_model_autogenerated") |
| |
| if config.llvm_raevict_model_autogenerated: |
| config.available_features.add("llvm_raevict_model_autogenerated") |
| |
| |
| def have_cxx_shared_library(): |
| readobj_exe = lit.util.which("llvm-readobj", config.llvm_tools_dir) |
| if not readobj_exe: |
| print("llvm-readobj not found") |
| return False |
| |
| try: |
| readobj_cmd = subprocess.Popen( |
| [readobj_exe, "--needed-libs", readobj_exe], stdout=subprocess.PIPE |
| ) |
| except OSError: |
| print("could not exec llvm-readobj") |
| return False |
| |
| readobj_out = readobj_cmd.stdout.read().decode("ascii") |
| readobj_cmd.wait() |
| |
| regex = re.compile(r"(libc\+\+|libstdc\+\+|msvcp).*\.(so|dylib|dll)") |
| needed_libs = False |
| for line in readobj_out.splitlines(): |
| if "NeededLibraries [" in line: |
| needed_libs = True |
| if "]" in line: |
| needed_libs = False |
| if needed_libs and regex.search(line.lower()): |
| return True |
| return False |
| |
| |
| if have_cxx_shared_library(): |
| config.available_features.add("cxx-shared-library") |
| |
| if config.libcxx_used: |
| config.available_features.add("libcxx-used") |
| |
| # LLVM can be configured with an empty default triple |
| # Some tests are "generic" and require a valid default triple |
| if config.target_triple: |
| config.available_features.add("default_triple") |
| # Direct object generation |
| if not config.target_triple.startswith(("nvptx", "xcore")): |
| config.available_features.add("object-emission") |
| |
| if config.have_llvm_driver: |
| config.available_features.add("llvm-driver") |
| |
| import subprocess |
| |
| |
| def have_ld_plugin_support(): |
| if not os.path.exists( |
| os.path.join(config.llvm_shlib_dir, "LLVMgold" + config.llvm_shlib_ext) |
| ): |
| return False |
| |
| ld_cmd = subprocess.Popen( |
| [config.gold_executable, "--help"], stdout=subprocess.PIPE, env={"LANG": "C"} |
| ) |
| ld_out = ld_cmd.stdout.read().decode() |
| ld_cmd.wait() |
| |
| if not "-plugin" in ld_out: |
| return False |
| |
| # check that the used emulations are supported. |
| emu_line = [l for l in ld_out.split("\n") if "supported emulations" in l] |
| if len(emu_line) != 1: |
| return False |
| emu_line = emu_line[0] |
| fields = emu_line.split(":") |
| if len(fields) != 3: |
| return False |
| emulations = fields[2].split() |
| if "elf_x86_64" not in emulations: |
| return False |
| if "elf32ppc" in emulations: |
| config.available_features.add("ld_emu_elf32ppc") |
| |
| ld_version = subprocess.Popen( |
| [config.gold_executable, "--version"], stdout=subprocess.PIPE, env={"LANG": "C"} |
| ) |
| if not "GNU gold" in ld_version.stdout.read().decode(): |
| return False |
| ld_version.wait() |
| |
| return True |
| |
| |
| if have_ld_plugin_support(): |
| config.available_features.add("ld_plugin") |
| |
| |
| def have_ld64_plugin_support(): |
| if not os.path.exists( |
| os.path.join(config.llvm_shlib_dir, "libLTO" + config.llvm_shlib_ext) |
| ): |
| return False |
| |
| if config.ld64_executable == "": |
| return False |
| |
| ld_cmd = subprocess.Popen([config.ld64_executable, "-v"], stderr=subprocess.PIPE) |
| ld_out = ld_cmd.stderr.read().decode() |
| ld_cmd.wait() |
| |
| if "ld64" not in ld_out or "LTO" not in ld_out: |
| return False |
| |
| return True |
| |
| |
| if have_ld64_plugin_support(): |
| config.available_features.add("ld64_plugin") |
| |
| # Ask llvm-config about asserts |
| llvm_config.feature_config( |
| [ |
| ("--assertion-mode", {"ON": "asserts"}), |
| ("--build-mode", {"[Dd][Ee][Bb][Uu][Gg]": "debug"}), |
| ] |
| ) |
| |
| if "darwin" == sys.platform: |
| cmd = ["sysctl", "hw.optional.fma"] |
| sysctl_cmd = subprocess.Popen(cmd, stdout=subprocess.PIPE) |
| |
| # Non zero return, probably a permission issue |
| if sysctl_cmd.wait(): |
| print( |
| 'Warning: sysctl exists but calling "{}" failed, defaulting to no fma3.'.format( |
| " ".join(cmd) |
| ) |
| ) |
| else: |
| result = sysctl_cmd.stdout.read().decode("ascii") |
| if "hw.optional.fma: 1" in result: |
| config.available_features.add("fma3") |
| |
| if not hasattr(sys, "getwindowsversion") or sys.getwindowsversion().build >= 17063: |
| config.available_features.add("unix-sockets") |
| |
| # .debug_frame is not emitted for targeting Windows x64, aarch64/arm64, AIX, or Apple Silicon Mac. |
| if not re.match( |
| r"^(x86_64|aarch64|arm64|powerpc|powerpc64).*-(windows-gnu|windows-msvc|aix)", |
| config.target_triple, |
| ) and not re.match(r"^arm64(e)?-apple-(macos|darwin)", config.target_triple): |
| config.available_features.add("debug_frame") |
| |
| if config.enable_threads: |
| config.available_features.add("thread_support") |
| |
| if config.have_libxml2: |
| config.available_features.add("libxml2") |
| |
| if config.have_curl: |
| config.available_features.add("curl") |
| |
| if config.have_httplib: |
| config.available_features.add("httplib") |
| |
| if config.have_opt_viewer_modules: |
| config.available_features.add("have_opt_viewer_modules") |
| |
| if config.expensive_checks: |
| config.available_features.add("expensive_checks") |
| |
| if "MemoryWithOrigins" in config.llvm_use_sanitizer: |
| config.available_features.add("use_msan_with_origins") |
| |
| |
| # Some tools support an environment variable "OBJECT_MODE" on AIX OS, which |
| # controls the kind of objects they will support. If there is no "OBJECT_MODE" |
| # environment variable specified, the default behaviour is to support 32-bit |
| # objects only. In order to not affect most test cases, which expect to support |
| # 32-bit and 64-bit objects by default, set the environment variable |
| # "OBJECT_MODE" to 'any' by default on AIX OS. |
| if "system-aix" in config.available_features: |
| config.environment["OBJECT_MODE"] = "any" |
| |
| if config.has_logf128: |
| config.available_features.add("has_logf128") |