Skip to content

Commit 8b719e9

Browse files
[SYCL][NFC] Re-enable, fix and upgrade headers testing (#16117)
We have a suite to check that every header contains enough `#include` directives and forward declarations so that it can be included standalone and used. However, that suite got accidentally disabled some time ago in #14879 This PR re-enabled the suite and fixed all issues it detected. Besides that, the suite is upgraded: - it now scans source directory, meaning that it won't complain about headers which were removed from the codebase, but left in build folder - it is now possible to have add a custom test instead of auto-generated one: this is useful when you want to trigger certain template instantiations to make sure that all code paths are covered
1 parent 5e61f8f commit 8b719e9

File tree

9 files changed

+136
-23
lines changed

9 files changed

+136
-23
lines changed

sycl/include/sycl/detail/id_queries_fit_in_int.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
#ifndef __SYCL_DEVICE_ONLY__
2424

2525
#include <sycl/exception.hpp>
26+
#include <sycl/nd_range.hpp>
27+
#include <sycl/range.hpp>
2628

2729
#include <limits>
2830
#include <type_traits>

sycl/include/sycl/ext/oneapi/backend/hip.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
#pragma once
1010

11-
#include <sycl/backend_types.hpp>
11+
#include <sycl/backend.hpp>
1212
#include <sycl/detail/backend_traits_hip.hpp>
1313

1414
namespace sycl {

sycl/include/sycl/ext/oneapi/experimental/raw_kernel_arg.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ namespace sycl {
1414
inline namespace _V1 {
1515

1616
class handler;
17+
namespace detail {
18+
class dynamic_parameter_impl;
19+
}
1720

1821
namespace ext::oneapi::experimental {
1922

sycl/include/sycl/ext/oneapi/experimental/virtual_functions.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
#pragma once
22

33
#include <sycl/ext/oneapi/properties/property.hpp>
4+
#include <sycl/ext/oneapi/properties/property_utils.hpp>
45
#include <sycl/ext/oneapi/properties/property_value.hpp>
56

7+
#include <utility>
8+
69
namespace sycl {
710
inline namespace _V1 {
811
namespace ext::oneapi::experimental {

sycl/include/sycl/ext/oneapi/experimental/work_group_memory.hpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,18 @@
77

88
#pragma once
99

10+
#include <sycl/access/access.hpp>
11+
#include <sycl/detail/defines.hpp>
12+
#include <sycl/ext/oneapi/properties/properties.hpp>
13+
#include <sycl/multi_ptr.hpp>
14+
15+
#include <cstddef>
1016
#include <type_traits>
1117

1218
namespace sycl {
1319
inline namespace _V1 {
20+
class handler;
21+
1422
namespace detail {
1523
template <typename T> struct is_unbounded_array : std::false_type {};
1624

@@ -37,8 +45,10 @@ namespace ext::oneapi::experimental {
3745

3846
struct indeterminate_t {};
3947
inline constexpr indeterminate_t indeterminate;
40-
4148
template <typename DataT, typename PropertyListT = empty_properties_t>
49+
class work_group_memory;
50+
51+
template <typename DataT, typename PropertyListT>
4252
class __SYCL_SPECIAL_CLASS __SYCL_TYPE(work_group_memory) work_group_memory
4353
: sycl::detail::work_group_memory_impl {
4454
public:

sycl/test/format.py

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,26 +5,57 @@
55
import os
66
import re
77

8-
SUFFIXES = {".hpp"}
9-
10-
118
class SYCLHeadersTest(lit.formats.TestFormat):
129
def getTestsForPath(
1310
self, testSuite, path_in_suite, filepath, litConfig, localConfig
1411
):
12+
# path_in_suite is a tuple like:
13+
# ('self-contained-headers', 'path/to', 'file.hpp')
14+
test_path = testSuite.getSourcePath(path_in_suite) + ".cpp"
15+
if os.path.exists(test_path):
16+
# We have a dedicated special test for a header, let's use a file
17+
# from the suite itself
18+
19+
# None is a special value we use to distinguish those two cases
20+
filepath = None
21+
# The actual file has .cpp extension as every other test
22+
path_in_suite = path_in_suite[:-1] + (path_in_suite[-1] + ".cpp",)
23+
else:
24+
# We don't have a dedicated special test for a header, therefore we
25+
# fallback to a generalized version of it
26+
27+
# SYCL headers may depend on some generated files and therefore we
28+
# use headers from the build folder for testing
29+
filepath = os.path.join(localConfig.sycl_include, *path_in_suite[1:])
30+
1531
yield lit.Test.Test(testSuite, path_in_suite, localConfig, file_path=filepath)
1632

1733
def getTestsInDirectory(self, testSuite, path_in_suite, litConfig, localConfig):
18-
# We traverse build/sycl/include/sycl directory
19-
source_path = os.path.join(localConfig.sycl_include, "sycl")
34+
# To respect SYCL_LIB_DUMPS_ONLY mode
35+
if ".cpp" not in localConfig.suffixes:
36+
return
37+
38+
# As we add more files and folders into 'self-contained-headers', this
39+
# method will be recursivelly called for them by lit discovery.
40+
# However, we don't use the test folder as the source of tests but
41+
# instead we use SYCL_SOURCE_DIR/include/sycl directory.
42+
# Therefore, we exit early from here if `path_in_suite` conatins more
43+
# than one element
44+
assert path_in_suite[0] == "self-contained-headers"
45+
if len(path_in_suite) > 1:
46+
return
47+
48+
source_path = os.path.join(localConfig.sycl_include_source_dir, "sycl")
2049

2150
# Optional filter can be passed through command line options
2251
headers_filter = localConfig.sycl_headers_filter
2352
for dirpath, _, filenames in os.walk(source_path):
24-
relative_dirpath = dirpath[len(localConfig.sycl_include) + 1 :]
53+
relative_dirpath = dirpath[len(localConfig.sycl_include_source_dir) + 1 :]
2554
for filename in filenames:
2655
suffix = os.path.splitext(filename)[1]
27-
if suffix not in SUFFIXES or suffix not in litConfig.suffixes:
56+
# We only look at actual header files and not at their .inc/.def
57+
# components
58+
if suffix != ".hpp":
2859
continue
2960
filepath = os.path.join(dirpath, filename)
3061

@@ -46,6 +77,18 @@ def getTestsInDirectory(self, testSuite, path_in_suite, litConfig, localConfig):
4677
yield t
4778

4879
def execute(self, test, litConfig):
80+
if test.file_path is None:
81+
# It means that we have a special test case for a header and we need
82+
# to execute it as a regular lit sh test
83+
return lit.TestRunner.executeShTest(
84+
test,
85+
litConfig,
86+
False, # execute_external
87+
[], # extra_substitutions
88+
[], # preamble_commands
89+
)
90+
91+
# Otherwise we generate the test on the fly
4992
command = [
5093
test.config.clang,
5194
"-fsycl",

sycl/test/lit.site.cfg.py.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ config.sycl_tools_dir = lit_config.params.get('SYCL_TOOLS_DIR', "@LLVM_TOOLS_DIR
99
config.sycl_include = lit_config.params.get('SYCL_INCLUDE', "@SYCL_INCLUDE@")
1010
config.sycl_obj_root = "@SYCL_BINARY_DIR@"
1111
config.sycl_source_dir = "@SYCL_SOURCE_DIR@/source"
12+
config.sycl_include_source_dir = "@SYCL_SOURCE_DIR@/include"
1213
config.sycl_libs_dir = lit_config.params.get('SYCL_LIBS_DIR', "@LLVM_LIBS_DIR@")
1314
config.target_triple = "@LLVM_TARGET_TRIPLE@"
1415
config.host_triple = "@LLVM_HOST_TRIPLE@"

sycl/test/self-contained-headers/README.md

Lines changed: 49 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,38 @@ still be sure that we haven't accidentally removed a necessary `#include`.
1414
meaning that any warnings coming out of them may be turned into errors and will
1515
affect test results. This is considered as an extra feature of the suite.
1616

17+
**One more note:** due to templated nature of SYCL headers, not every code path
18+
may be instantiated by a mere `#include` and therefore not every dependency will
19+
be highlighted by a simple test. To overcome this, there is an ability to write
20+
dedicated tests for certain headers which are more exhaustive than a simple
21+
`#include`, see more details below.
22+
1723
## Implementation
1824

1925
There was a couple of iterations on the suite design and its current shape
2026
features the following:
21-
- each header in `build/include/sycl` is checked as a separate test
22-
- each such test is generated on the fly dynamically during LIT discovery phase
27+
- each header in `build/include/sycl` is checked as a separate test, unless:
28+
- it doesn't exists in `source/include/sycl`, meaning that it is likely
29+
removed from the codebase, but still resides in `build/` directory
30+
- **TODO:** we also have some auto-generated headers which could be skipped
31+
this way, we need to consider a mechanism to handle them as well
32+
- **TODO:** presence of outdated headers in `build` directory should also be
33+
detected, or otherwise it can lead to compilation issues being hidden in
34+
local setup
35+
- each such test is generated on the fly dynamically during LIT discovery phase,
36+
unless:
37+
- there is a special/dedicated test for a header, more details below
2338

2439
That is done to allow for massive parallelism and keep those tests small and
2540
quick.
2641

27-
Absolute most of the magic is happenning within
42+
Absolute most of the magic is happening within
2843
[`sycl/test/format.py`](/sycl/test/format.py): we define a custom test format in
2944
there which overrides standard discovery and test execution rules.
3045

3146
## How to use and maintain
3247

33-
Those tests are part of `check-sycl` target and you can pass a regexp acepted
48+
Those tests are part of `check-sycl` target and you can pass a regexp accepted
3449
by Python's `re` package as `SYCL_HEADERS_FILTER` parameter to LIT to filter
3550
which headers you would like to see checked (only those that match the passed
3651
regexp will be used to generate tests).
@@ -47,11 +62,38 @@ Documentation for Python's regexp can be found [here][python-3-re].
4762

4863
[python-3-re]: https://docs.python.org/3/library/re.html#regular-expression-syntax
4964

50-
Since there are no dedicated files for each test, `XFAIL`ing them using regular
51-
method is impossible, but it is still supported. To do so, open
65+
Since there are no dedicated files for auto-generated tests, `XFAIL`ing them
66+
using regular method is impossible, but it is still supported. To do so, open
5267
[the local config](/sycl/test/self-contained-headers/lit.local.cfg) and modify
5368
list of files which should be treated as expected to fail.
5469

70+
### Special tests
71+
72+
As noted above, to truly ensure that SYCL headers are self-contained, we need
73+
not only include them, but also use them
74+
(read: instantiate all classes and methods).
75+
76+
To support that, for every SYCL header we have in `source/include/sycl` the tool
77+
first checks if there is a corresponding test file in
78+
`source/test/self-contained-headers` and if so, it is used instead of an
79+
auto-generated one.
80+
81+
Those special tests should be named and located in certain place to be detected,
82+
or otherwise they will be ignored. For a header
83+
`source/include/sycl/path/to/header.hpp` its special test should be placed under
84+
`source/test/sycl/self-contained-headers/sycl/path/to/header.hpp.cpp`.
85+
86+
Note a few things: directory structure should exactly match, the filename should
87+
be the same as the header file name, but with `.cpp` extension added on top of
88+
it.
89+
90+
Those special tests will be treated as any other regular Sh-based tests, i.e.
91+
you should write your regular `RUN` lines in there. It is expected that those
92+
tests will run a compilation under `-fsyntax-only` mode and verify absence of
93+
any compilation errors or warnings through `-Xclang -verify` mechanism.
94+
95+
Special tests can be `XFAIL`-ed using a regular LIT mechanism.
96+
5597
## Known issues and quirks
5698

5799
### To launch the suite directly, use `LIT_FILTER` env variable
@@ -70,14 +112,7 @@ Instead, the following approach should be used:
70112
LIT_FILTER='self-contained-headers' llvm-lit sycl/test
71113
```
72114

73-
### Old legacy files in build/ area are still checked
74-
75-
The custom discovery script uses `build/include/sycl/` folder contents to
76-
generate tests for each header it finds there. It means that if some header was
77-
removed from the codebase, it may still be present in `build` folder unless
78-
some cleanup is performed.
79-
80-
### No OS-specific `XFAIL` mechanism is implemented
115+
### No OS-specific `XFAIL` mechanism is implemented for auto-generated tests
81116

82117
`XFAIL` mechanism mentioned in "How to use and maintain" section does not
83118
support marking a test as expected to fail only in certain environment, which
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// RUN: %clangxx -fsycl -fsyntax-only -Xclang -verify %s
2+
// expected-no-diagnostics
3+
//
4+
// The purpose of this test is to ensure that the header containing
5+
// sycl::handler class definition is self-contained, i.e. we can use handler
6+
// and no extra headers are needed.
7+
//
8+
// TODO: the test should be expanded to use various methods of the class. Due
9+
// to their template nature we may not test all code paths until we trigger
10+
// instantiation of a corresponding method.
11+
12+
#include <sycl/handler.hpp>
13+
14+
class kernel_name;
15+
16+
void foo(sycl::handler &h) {}

0 commit comments

Comments
 (0)