Contributing to DPC++¶
General guidelines¶
Read CONTRIBUTING.md first.
Maintaining stable ABI/API¶
All changes made to the DPC++ compiler and runtime library should generally preserve existing ABI/API and contributors should avoid making incompatible changes. One of the exceptions is experimental APIs, clearly marked so by namespace or related specification. If you wish to propose a new experimental DPC++ extension then read README-process.md.
Another exceptional case is the transition from SYCL 1.2.1 to SYCL 2020 standard.
Deprecation of older APIs is happening in the following order:
Newer API implemented and covered with tests
Deprecation warning is added to older API
Wait some time allowing users to migrate their codebases (exact period depends on the change made)
Old API is removed in headers
Old API is removed in library
See ABI Policy Guide for more information.
Project build and local testing¶
Commit message¶
For any DPC++-related commit, the [SYCL]
tag should be present in the
commit message title. To a reasonable extent, additional tags can be used
to signify the component changed, e.g.: [UR]
, [CUDA]
, [Doc]
.
Using <iostream>¶
According to
LLVM Coding Standards,
the use #include <iostream>
is forbidden in library files. Instead, the
sycl/detail/iostream_proxy.hpp header offers the functionality of
Tests development¶
Every product change should be accompanied with corresponding test modification (adding new test(s), extending, removing or modifying existing test(s)).
There are 3 types of tests which are used for DPC++ toolchain validation:
DPC++ device-independent tests
DPC++ end-to-end (E2E) tests
SYCL Conformance Test Suite (CTS)
DPC++ device-independent tests¶
DPC++ device-independent tests are hosted in this repository. They can be run by check-llvm, check-clang, check-llvm-spirv and check-sycl targets. These tests are expected not to have hardware (e.g. GPU, FPGA, etc.) or external software (e.g. OpenCL, Level Zero, CUDA runtimes) dependencies. All other tests should land at DPC++ end-to-end or SYCL CTS tests.
Generally, any functional change to any of the DPC++ toolchain components should be accompanied by one or more tests of this type when possible. They allow verifying individual components and tend to be more lightweight than end-to-end or SYCL-CTS tests.
General guidelines¶
Use
sycl::
namespace instead ofcl::sycl::
Add a helpful comment describing what the test does at the beginning and other comments throughout the test as necessary.
All identifiers used in
llvm/sycl
headers files must contain at least one lowercase letter due to avoid conflicts with user-defined macros.Try to follow descriptive naming convention for variables, functions as much as possible. Please refer to LLVM naming convention
DPC++ clang FE tests¶
Include sycl mock headers as system headers. Example:
-internal-isystem %S/Inputs
`#include "sycl.hpp"`
Use SYCL functions for invoking kernels from the mock header
(single_task, parallel_for, parallel_for_work_group)
Example:`#include "Inputs/sycl.hpp"` sycl::queue q; q.submit([&](sycl::handler &h) { h.single_task( { //code }); });
DPC++ headers and runtime tests¶
check-sycl target contains 2 types of tests: LIT tests and unit tests. LIT tests make compile-time checks of DPC++ headers, e.g. device code IR verification,
static_assert
tests. Unit tests check DPC++ runtime behavior and do not perform any device code compilation, instead relying on redefining the UR API with UrMock and the Unified Runtime mocking interface when necessary.
When adding new test to check-sycl
, please consider the following:
if you only need to check that compilation succeeds, please use
-fsyntax-only
compiler flag for such tests: it instructs the compiler to launch reduced set of commands and produce no output (no need to add-o %t.out
).if you are only interested in checking device or host compilation, please use corresponding flags to reduce the scope of test and therefore speed it up. To launch only device compilation, use
-fsycl-device-only
compiler flag; to launch only host compilation, use%fsycl-host-only
substitution.tests which want to check generated device code (either in LLVM IR or SPIR-V form) should be placed under check_device_code folder.
if compiler invocation in your LIT test produces an output file, please make sure to redirect it into a temporary file using
-o
option and%t
substitution. This is needed to avoid possible race conditions when two LIT tests attempt to write into the same file.if you need to check some runtime behavior please add unit test instead of LIT test. Unit tests are built with regular C++ compiler which is used to build the project and therefore they are not affected by
clang++
being slow when the project is built in Debug mode. As another side effect of using standard C++ compiler, device side compilation is skipped entirely, making them quicker to compile. And finally, unit tests are written with googletest framework, which allows to use plenty of useful assertions and other helpers.
DPC++ end-to-end (E2E) tests¶
These tests are located in /sycl/test-e2e directory and are not configured to be run by default. See End-to-End tests documentation for instructions on how to run them.
A test which requires full stack including backend runtimes (e.g. OpenCL, Level Zero or CUDA) should be added to DPC++ E2E tests.
SYCL Conformance Test Suite (CTS)¶
These tests are hosted at Khronos SYCL conformance tests. These tests verify SYCL specification conformance. All implementation details are out of scope for the tests. See DPC++ compiler invocation definitions at FindIntel_SYCL)
Unified Runtime Updates¶
To integrate changes from the Unified Runtime project into DPC++ there two main options which depend on the scope of those changes and the current state of DPC++.
Synchronized update:
When: If the Unified Runtime change touches the API/ABI, more than one adapter, or common code such as the loader.
How: Update the
UNIFIED_RUNTIME_TAG
to point at the desired commit or tag name in the Unified Runtime repository and ensure that any tag for specific adapters are set to use${UNIFIED_RUNTIME_TAG}
.
Decoupled update:
When: If only a single Unified Runtime adatper has changed.
How: Update the tag used in the
fetch_adapter_source()
call for a specific Unified Runtime adapter, e.g. Level Zero, OpenCL, CUDA, HIP, or Native CPU.
In general, a synchronized update should be the default. However, when there are a lot of changes in flight in parallel always synchronizing the tag can be troublesome. This is when a decoupled update can help sustain the merge velocity of Unified Runtime changes.
The intel/unified-runtime-reviewers team is responsible for ensuring that the Unified Runtime tag is updated correctly and will only provide code owner approval to pull requests once the following criteria are met:
Tags are pointing to a valid commit or tag on Unified Runtime main branch.
Changes to additional code owned files are in a good state.
GitHub Actions checks are passing.