Skip to content

Commit 8a27954

Browse files
authored
[SYCL][E2E] Add logic to react to REQUIRED/UNSUPPORTED in build-only (#16725)
Adds logic for evaluating `REQUIRES`/`UNSUPPORTED` statements on `build-only` mode by "ignoring" features in these statements that do not affect the compilation (Everything other than OS, triple, and SDK/libraries). More precisely, the ability to ignore features is implemented by extending the boolean expressions to use a third boolean state - `ignore`. If a particular sub-expression includes an `ignore`, and if its result could be changed by setting that `ignore` to either `true` or `false`, then the result of that sub-expression is set to `ignore`. For example `ignore || true = true`, but `ignore || false = ignore`, this is because in the first example there would be no way to set the ignore such that the result is anything other than `true`, while in the second example the result is dependent on the "actual" value of the `ignore`. If the resulting value of a `REQUIRES` predicate is `ignore` we interpret that as `true` (The requirements were met), on the other hand for `UNSUPPORTED` predicates we would interpret `ignore` as `false` instead (The unsupported criteria was not met). The triples that can be used for a given test are then selected by evaluating the `REQUIRES`/`UNSUPPORTED` with the set of features + the target feature corresponding to each triple (mirroring the way we select devices), while ignoring all features that do not affect compilation. The target features available are the following: `target-spir`, `target-amd`, `target-nvidia`, and `target-native_cpu`. Each of these map to a triple. Similarly to how `XFAIL` is handled when using multiple devices if we are compiling for multiple triples, and a single triple is marked as `XFAIL`, then it is treated as unsupported instead. The available target triples in `build-only` mode is determined through the use of the `sycl_build_targets` lit param (i.e., `--param sycl_build_targets=spir;amd`). This is currently set to only `spir`, as the changes in test markup included in this pr do not take into account building for `nvptx` and `amdgcn` triples. In `run-only` and `full` mode the available triples are determined via the available devices.
1 parent 0dcc42e commit 8a27954

28 files changed

+311
-74
lines changed

sycl/test-e2e/AmdNvidiaJIT/kernel_and_bundle.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
// UNSUPPORTED: windows
2-
// REQUIRES: cuda || hip
3-
// REQUIRES: build-and-run-mode
2+
// REQUIRES: target-nvidia || target-amd
43

54
// This test relies on debug output from a pass, make sure that the compiler
65
// can generate it.

sycl/test-e2e/Basic/windows_version_agnostic_sycl_lib.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
// REQUIRES: windows
2-
// REQUIRES: build-and-run-mode
32

43
// RUN: %clangxx --driver-mode=cl /std:c++17 /EHsc %sycl_include -I%opencl_include_dir %s -o %t.out /link /defaultlib:%sycl_static_libs_dir/sycl.lib
54
// RUN: %{run} %t.out
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
// using --offload-compress without zstd should throw an error.
22
// REQUIRES: !zstd
3-
// REQUIRES: build-and-run-mode
43
// RUN: not %{build} %O0 -g --offload-compress %S/Inputs/single_kernel.cpp -o %t_compress.out 2>&1 | FileCheck %s
54
// CHECK: '--offload-compress' option is specified but zstd is not available. The device image will not be compressed.

sycl/test-e2e/DeviceLib/math_fp64_windows_test.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
// REQUIRES: aspect-fp64, windows
2-
// REQUIRES: build-and-run-mode
32

43
// DEFINE: %{mathflags} = %if cl_options %{/clang:-fno-fast-math%} %else %{-fno-fast-math%}
54

sycl/test-e2e/DeviceLib/math_windows_test.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
// REQUIRES: windows
2-
// REQUIRES: build-and-run-mode
32

43
// TODO: Add hypotf case back when the missing symbol is fixed.
54

sycl/test-e2e/E2EExpr.py

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
from lit.BooleanExpression import BooleanExpression
2+
3+
4+
class E2EExpr(BooleanExpression):
5+
build_specific_features = {
6+
"build-and-run-mode",
7+
"target-spir",
8+
"target-nvidia",
9+
"target-amd",
10+
"target-native_cpu",
11+
"any-target-is-spir",
12+
"any-target-is-nvidia",
13+
"any-target-is-amd",
14+
"any-target-is-native_cpu",
15+
"linux",
16+
"system-linux",
17+
"windows",
18+
"system-windows",
19+
"enable-perf-tests",
20+
"preview-breaking-changes-supported",
21+
"has_ndebug",
22+
"ocloc",
23+
"opencl-aot",
24+
"opencl_icd",
25+
"cm-compiler",
26+
"xptifw",
27+
"level_zero_dev_kit",
28+
"cuda_dev_kit",
29+
"zstd",
30+
"vulkan",
31+
"true",
32+
"false",
33+
}
34+
35+
def __init__(self, string, variables, build_only_mode, final_unknown_value):
36+
BooleanExpression.__init__(self, string, variables)
37+
self.build_only_mode = build_only_mode
38+
self.unknown = False
39+
self.final_unknown_value = final_unknown_value
40+
41+
@staticmethod
42+
def evaluate(string, variables, build_only_mode, final_unknown_value=True):
43+
"""
44+
string: Expression to evaluate
45+
variables: variables that evaluate to true
46+
build_only_mode: if true enables unknown values
47+
final_unknown_value: final boolean result if evaluation results in `unknown`
48+
"""
49+
try:
50+
parser = E2EExpr(
51+
string, set(variables), build_only_mode, final_unknown_value
52+
)
53+
return parser.parseAll()
54+
except ValueError as e:
55+
raise ValueError(str(e) + ("\nin expression: %r" % string))
56+
57+
def parseMATCH(self):
58+
token = self.token
59+
BooleanExpression.parseMATCH(self)
60+
if token not in self.build_specific_features and self.build_only_mode:
61+
self.unknown = True
62+
else:
63+
self.unknown = False
64+
if self.value and self.unknown:
65+
raise ValueError(
66+
'Runtime feature "' + token + '" evaluated to True in build-only'
67+
)
68+
69+
def parseAND(self):
70+
self.parseNOT()
71+
while self.accept("&&"):
72+
left = self.value
73+
left_unknown = self.unknown
74+
self.parseNOT()
75+
right = self.value
76+
right_unknown = self.unknown
77+
self.value = left and right
78+
# Unknown if both are unknown or if one is true and the other is unknown
79+
self.unknown = (
80+
(left_unknown and right_unknown)
81+
or (left_unknown and right)
82+
or (left and right_unknown)
83+
)
84+
85+
def parseOR(self):
86+
self.parseAND()
87+
while self.accept("||"):
88+
left = self.value
89+
left_unknown = self.unknown
90+
self.parseAND()
91+
right = self.value
92+
right_unknown = self.unknown
93+
self.value = left or right
94+
# Unknown if both are unknown or if one is false and the other is unknown
95+
self.unknown = (
96+
(left_unknown and right_unknown)
97+
or (left_unknown and not right)
98+
or (not left and right_unknown)
99+
)
100+
101+
def parseAll(self):
102+
self.token = next(self.tokens)
103+
self.parseOR()
104+
self.expect(BooleanExpression.END)
105+
return self.final_unknown_value if self.unknown else self.value
106+
107+
108+
import unittest
109+
110+
111+
class TestE2EExpr(unittest.TestCase):
112+
def test_basic(self):
113+
BuildOnly = True
114+
BuildAndRun = False
115+
RequiresDirective = True
116+
UnsupportedDirective = False
117+
RegularEval = lambda expr, features: E2EExpr.evaluate(
118+
expr, features, BuildAndRun
119+
)
120+
RequiresBuildEval = lambda expr, features: E2EExpr.evaluate(
121+
expr, features, BuildOnly, RequiresDirective
122+
)
123+
UnsupportedBuildEval = lambda expr, features: E2EExpr.evaluate(
124+
expr, features, BuildOnly, UnsupportedDirective
125+
)
126+
# Non build-only expressions should work the same
127+
self.assertTrue(RegularEval("linux", {"linux", "rt_feature"}))
128+
self.assertTrue(RegularEval("rt_feature", {"linux", "rt_feature"}))
129+
self.assertFalse(
130+
RegularEval("rt_feature1 && rt_feature2", {"linux", "rt_feature1"})
131+
)
132+
# build-only expressions with no unknowns should work the same
133+
self.assertTrue(UnsupportedBuildEval("linux", {"linux"}))
134+
self.assertFalse(RequiresBuildEval("linux && windows", {"linux"}))
135+
self.assertTrue(UnsupportedBuildEval("!(windows || zstd)", {"linux"}))
136+
# build-only expressions where unknown affects the resulting value
137+
self.assertTrue(RequiresBuildEval("rt_feature", {}))
138+
self.assertFalse(UnsupportedBuildEval("rt_feature", {}))
139+
self.assertFalse(UnsupportedBuildEval("!rt_feature", {}))
140+
self.assertTrue(RequiresBuildEval("windows || rt_feature", {"linux"}))
141+
self.assertFalse(UnsupportedBuildEval("windows || rt_feature", {"linux"}))
142+
self.assertTrue(RequiresBuildEval("linux && rt_feature", {"linux"}))
143+
self.assertFalse(UnsupportedBuildEval("linux && rt_feature", {"linux"}))
144+
self.assertTrue(RequiresBuildEval("linux && !(zstd || rt_feature)", {"linux"}))
145+
self.assertFalse(
146+
UnsupportedBuildEval("linux && !(zstd || rt_feature)", {"linux"})
147+
)
148+
# build-only expressions where unknown does not affect the resulting value
149+
self.assertTrue(RequiresBuildEval("linux || rt_feature", {"linux"}))
150+
self.assertTrue(UnsupportedBuildEval("linux || rt_feature", {"linux"}))
151+
self.assertFalse(RequiresBuildEval("windows && rt_feature", {"linux"}))
152+
self.assertFalse(UnsupportedBuildEval("windows && rt_feature", {"linux"}))
153+
self.assertFalse(
154+
RequiresBuildEval("linux && (vulkan && rt_feature)", {"linux"})
155+
)
156+
self.assertFalse(
157+
UnsupportedBuildEval("linux && (vulkan && rt_feature)", {"linux"})
158+
)
159+
# runtime feature is present in build-only
160+
with self.assertRaises(ValueError):
161+
RequiresBuildEval("rt_feature", {"rt_feature"})
162+
with self.assertRaises(ValueError):
163+
UnsupportedBuildEval("rt_feature", {"rt_feature"})
164+
165+
166+
if __name__ == "__main__":
167+
unittest.main()

sycl/test-e2e/EnqueueNativeCommand/custom-command-cuda.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// RUN: %{build} -Wno-error=deprecated-declarations -o %t.out %cuda_options
22
// RUN: %{run} %t.out
33
// REQUIRES: cuda, cuda_dev_kit
4-
// REQUIRES: build-and-run-mode
54

65
#include <cuda.h>
76

sycl/test-e2e/EnqueueNativeCommand/custom-command-hip.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22
// we should set this with some variable instead.
33
// RUN: %{build} -Wno-error=deprecated-pragma -o %t.out -I%rocm_path/include -L%rocm_path/lib -lamdhip64
44
// RUN: %{run} %t.out
5-
// REQUIRES: hip
6-
// REQUIRES: build-and-run-mode
5+
// REQUIRES: target-amd
76

87
#include <iostream>
98
#include <sycl/backend.hpp>

sycl/test-e2e/EnqueueNativeCommand/custom-command-multiple-dev-cuda.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
// REQUIRES: cuda, cuda_dev_kit
2-
// REQUIRES: build-and-run-mode
32
// RUN: %{build} -o %t.out %cuda_options
43
// RUN: %{run} %t.out
54

sycl/test-e2e/HostInteropTask/interop-task-cuda-buffer-migrate.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
// REQUIRES: cuda, cuda_dev_kit
2-
// REQUIRES: build-and-run-mode
32
//
43
// RUN: %{build} -o %t.out %cuda_options
54
// RUN: %{run} %t.out

0 commit comments

Comments
 (0)