Skip to content

Commit 939a1d4

Browse files
authored
[ATfE] Set xfails indirectly instead of modifying test sources (#487)
Certain tests will fail when run with ATfE's compiler and libraries. The toolchain currently modifies the test sources to change the expected result, but this requires maintaining downstream patches. The LLVM test driver, lit, provides options to override the expected result set in the file through command line and environment variables, which would remove this burden. This patch makes use of the `LIT_XFAILS` and `LIT_XFAILS_NOT` environment variables, which will take precedence over what is set in the sources. A new script is provided which will generate a list of tests for a given project/library variant that are expected to give a different result. This is largely based on the existing set of downstream patches. This also has the advantage of allowing xfails to be set for specific variants, instead of globally. This currently only supports the clang, compiler-rt and libcxx projects. In order to prepare the correct environment for lit, a wrapper script is also provided which will accept files containing test lists to be loaded into the relevant environment variable. Since the test lists can be quite long, this prevents the command line getting significantly bloated.
1 parent 71bd352 commit 939a1d4

13 files changed

+514
-386
lines changed

arm-software/embedded/CMakeLists.txt

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -360,13 +360,37 @@ include(${CMAKE_CURRENT_SOURCE_DIR}/../shared/cmake/generate_toolchain_id.cmake)
360360
set(LLVM_EXTERNAL_PROJECTS elf2bin)
361361
set(LLVM_EXTERNAL_ELF2BIN_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../shared/elf2bin)
362362

363+
# Use the downstream version of lit, which is just a wrapper for the built one.
364+
# Pass it the xfail/xfail-not lists.
365+
set(llvm_xfails_file_path "${CMAKE_CURRENT_BINARY_DIR}/llvm.xfails")
366+
set(llvm_xfails_not_file_path "${CMAKE_CURRENT_BINARY_DIR}/llvm.upasses")
367+
# Set LLVM_DEFAULT_EXTERNAL_LIT and LLVM_LIT_ARGS before including the LLVM subdirectory.
368+
set(LLVM_DEFAULT_EXTERNAL_LIT "${CMAKE_CURRENT_SOURCE_DIR}/arm-runtimes/test-support/lit-wrapper.py")
369+
set(LLVM_LIT_ARGS "${LLVM_LIT_ARGS} -sv --real-lit-path=${CMAKE_CURRENT_BINARY_DIR}/llvm/bin/llvm-lit --xfails-file=${llvm_xfails_file_path} --xfails-not-file=${llvm_xfails_not_file_path}" CACHE STRING "")
370+
363371
set(llvmproject_src_dir ${CMAKE_CURRENT_SOURCE_DIR}/../..)
364372
add_subdirectory(
365373
${llvmproject_src_dir}/llvm llvm
366374
)
367375

368376
add_dependencies(check-all check-elf2bin)
369377

378+
# Generate a xfail/xfail-not list before running the tests.
379+
add_custom_target(
380+
llvm-xfail-files
381+
COMMAND ${Python3_EXECUTABLE}
382+
${CMAKE_CURRENT_SOURCE_DIR}/arm-runtimes/test-support/xfails.py
383+
--project llvm
384+
--clang ${LLVM_BINARY_DIR}/bin/clang
385+
--xfails_file ${llvm_xfails_file_path}
386+
--xfails_not_file ${llvm_xfails_not_file_path}
387+
DEPENDS
388+
clang
389+
)
390+
add_dependencies(check-clang llvm-xfail-files)
391+
add_dependencies(check-llvm llvm-xfail-files)
392+
add_dependencies(check-all llvm-xfail-files)
393+
370394
if(LLVM_TOOLCHAIN_C_LIBRARY STREQUAL llvmlibc)
371395
install(
372396
FILES
@@ -572,11 +596,6 @@ add_dependencies(
572596
version_txt
573597
)
574598

575-
# Set LLVM_DEFAULT_EXTERNAL_LIT to the directory of clang
576-
# which was build in previous step. This path is not exported
577-
# by add_subdirectory of llvm project
578-
set(LLVM_DEFAULT_EXTERNAL_LIT "${LLVM_BINARY_DIR}/bin/llvm-lit")
579-
580599
add_custom_target(check-llvm-toolchain-runtimes)
581600
add_custom_target(check-${LLVM_TOOLCHAIN_C_LIBRARY})
582601
add_custom_target(check-compiler-rt)

arm-software/embedded/arm-runtimes/CMakeLists.txt

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -271,9 +271,24 @@ if(VARIANT STREQUAL "armv6m_soft_nofp")
271271
endif()
272272

273273
if(ENABLE_COMPILER_RT_TESTS)
274+
# Use the downstream version of lit, which is just a wrapper for the built one.
275+
# Pass it the xfail/xfail-not lists.
276+
set(compiler_rt_xfails_file_path "${CMAKE_CURRENT_BINARY_DIR}/${VARIANT}_compiler-rt.xfails")
277+
set(compiler_rt_xfails_not_file_path "${CMAKE_CURRENT_BINARY_DIR}/${VARIANT}_compiler-rt.upasses")
274278
set(compiler_rt_test_flags "${lib_compile_flags} ${test_link_flags}")
275-
set(compiler_rt_lit_args "${LLVM_LIT_ARGS} --path=${LLVM_BINARY_DIR}/bin --xunit-xml-output=results.junit.xml")
276-
set(external_lit_path "${LLVM_BINARY_DIR}/bin/llvm-lit")
279+
set(compiler_rt_lit_args "${LLVM_LIT_ARGS} --path=${LLVM_BINARY_DIR}/bin --xunit-xml-output=results.junit.xml --real-lit-path=${LLVM_BINARY_DIR}/bin/llvm-lit --xfails-file=${compiler_rt_xfails_file_path} --xfails-not-file=${compiler_rt_xfails_not_file_path}"
280+
)
281+
set(external_lit_path "${CMAKE_CURRENT_SOURCE_DIR}/test-support/lit-wrapper.py")
282+
add_custom_target(
283+
compiler-rt-xfail-files
284+
COMMAND ${Python3_EXECUTABLE}
285+
${CMAKE_CURRENT_SOURCE_DIR}/test-support/xfails.py
286+
--variant ${VARIANT}
287+
--project compiler-rt
288+
--libc ${C_LIBRARY}
289+
--xfails_file ${compiler_rt_xfails_file_path}
290+
--xfails_not_file ${compiler_rt_xfails_not_file_path}
291+
)
277292
set(
278293
compiler_rt_test_cmake_args
279294
-DCOMPILER_RT_INCLUDE_TESTS=ON
@@ -366,6 +381,7 @@ if(ENABLE_COMPILER_RT_TESTS)
366381
check-compiler-rt
367382
compiler_rt-build
368383
clib-install
384+
compiler-rt-xfail-files
369385
)
370386
add_dependencies(check-compiler-rt compiler_rt-check-compiler-rt)
371387
endif()
@@ -797,7 +813,23 @@ if(ENABLE_CXX_LIBS)
797813
-DLIBCXX_ENABLE_RTTI=${ENABLE_RTTI}
798814
)
799815
if(ENABLE_LIBCXX_TESTS)
800-
set(cxxlibs_lit_args "${LLVM_LIT_ARGS} --xunit-xml-output=results.junit.xml")
816+
# Use the downstream version of lit, which is just a wrapper for the built one.
817+
# Pass it the xfail/xfail-not lists.
818+
set(libcxx_xfails_file_path "${CMAKE_CURRENT_BINARY_DIR}/${VARIANT}_libcxx.xfails")
819+
set(libcxx_xfails_not_file_path "${CMAKE_CURRENT_BINARY_DIR}/${VARIANT}_libcxx.upasses")
820+
set(external_lit_path "${CMAKE_CURRENT_SOURCE_DIR}/test-support/lit-wrapper.py")
821+
set(libcxx_lit_args "${LLVM_LIT_ARGS} -sv --xunit-xml-output=results.junit.xml --real-lit-path=${LLVM_BINARY_DIR}/bin/llvm-lit --xfails-file=${libcxx_xfails_file_path} --xfails-not-file=${libcxx_xfails_not_file_path}"
822+
)
823+
add_custom_target(
824+
libcxx-xfail-files
825+
COMMAND ${Python3_EXECUTABLE}
826+
${CMAKE_CURRENT_SOURCE_DIR}/test-support/xfails.py
827+
--variant ${VARIANT}
828+
--project libcxx
829+
--libc ${C_LIBRARY}
830+
--xfails_file ${libcxx_xfails_file_path}
831+
--xfails_not_file ${libcxx_xfails_not_file_path}
832+
)
801833
set(cxxlibs_test_cmake_options
802834
-DLIBCXX_TEST_CONFIG=${CMAKE_CURRENT_SOURCE_DIR}/test-support/llvm-libc++-picolibc.cfg.in
803835
-DLIBCXX_TEST_PARAMS=executor=${lit_test_executor}
@@ -807,7 +839,8 @@ if(ENABLE_CXX_LIBS)
807839
-DLIBUNWIND_TEST_PARAMS=executor=${lit_test_executor}
808840
-DRUNTIME_TEST_ARCH_FLAGS=${compile_arch_flags}
809841
-DRUNTIME_TEST_LINK_FLAGS=${test_link_flags}
810-
-DLLVM_LIT_ARGS=${cxxlibs_lit_args}
842+
-DLLVM_LIT_ARGS=${libcxx_lit_args}
843+
-DLLVM_EXTERNAL_LIT=${external_lit_path}
811844
)
812845
endif()
813846
elseif(C_LIBRARY STREQUAL llvmlibc)
@@ -940,6 +973,7 @@ if(ENABLE_CXX_LIBS)
940973
cxxlibs
941974
${check_target}
942975
cxxlibs-install
976+
libcxx-xfail-files
943977
)
944978
add_dependencies(${check_target} cxxlibs-${check_target})
945979
endforeach()
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#!/usr/bin/env python3
2+
3+
# SPDX-FileCopyrightText: Copyright 2024-2025 Arm Limited and/or its affiliates <[email protected]>
4+
5+
"""This is a wrapper script for LLVM's lit, which takes additional options in
6+
order to prepare a specific environment for running tests.
7+
8+
The new --xfails-file and --xfails-not-file options are functionally similar
9+
to the existing --xfails and --xfails-not options, but allow for a test
10+
list to be loaded from a file instead of on the command line. This is
11+
preferable when there are large number of tests that need to be specified."""
12+
13+
import argparse
14+
import os
15+
import runpy
16+
import sys
17+
18+
parser = argparse.ArgumentParser()
19+
parser.add_argument("--xfails-file")
20+
parser.add_argument("--xfails-not-file")
21+
parser.add_argument("--real-lit-path", required=True)
22+
# Only parse the known args above. The rest should be processed the actual lit.
23+
known_args, unknown_args = parser.parse_known_args()
24+
25+
26+
def load_env_var(env_var_name, input_filename):
27+
"""Load the contents of a file into an environment variable."""
28+
if input_filename:
29+
if os.path.isfile(input_filename):
30+
with open(input_filename, "r", encoding="utf-8") as f:
31+
xfail_lines = f.readlines()
32+
lit_xfails_list = ";".join([line.strip() for line in xfail_lines])
33+
# Load the contents of the file into variables
34+
if env_var_name in os.environ:
35+
os.environ[env_var_name] = (
36+
os.environ[env_var_name] + ";" + lit_xfails_list
37+
)
38+
else:
39+
os.environ[env_var_name] = lit_xfails_list
40+
else:
41+
raise FileNotFoundError(
42+
f"Error: Expected file '{input_filename}' does not exist."
43+
)
44+
45+
46+
load_env_var("LIT_XFAIL", known_args.xfails_file)
47+
load_env_var("LIT_XFAIL_NOT", known_args.xfails_not_file)
48+
49+
# Remove expected custom args from the arg list.
50+
new_argv = [sys.argv[0]] + unknown_args
51+
sys.argv = new_argv
52+
53+
# Run lit with the new arg list.
54+
runpy.run_path(known_args.real_lit_path, run_name="__main__")

0 commit comments

Comments
 (0)