Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 38 additions & 4 deletions sycl/test/basic_tests/device_only_no_iostream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// any compilation pass, including device. Customers compile their device
// code with -fsycl-device-only and expect a clean dependency graph; pulling
// the standard iostream machinery breaks that contract by introducing
// host-only globals (std::cin/cout/cerr) and ios_base::Init static
// globals (std::cin/cout/cerr) and ios_base::Init static
// initializers that fail in device JIT/AOT pipelines.
//
// This test enforces that contract for every KHR header by compiling a
Expand All @@ -15,6 +15,30 @@
// offending stream code into the SYCL runtime (sycl/source/...) and keep
// the header device-clean.
//
// We enforce the contract with TWO complementary guards, because the -MD
// dependency list is flat (it records that a header was reached, not who
// pulled it in):
//
// 1. A FileCheck pass over the -MD list that rejects the iostream
// machinery -- <iostream>, the iostream_proxy shim, and the C-style
// *.h stream headers. These are never dragged in by <iterator>; their
// presence means real std::cin/cout/cerr globals and an ios_base::Init
// static initializer entered the graph.
//
// 2. A source-grep guard that rejects any *raw* `#include <ostream>`,
// <istream>, <iostream> or <sstream> written in a SYCL header that the
// KHR umbrella actually reaches. This is what catches an author adding a
// stream include to a KHR-reachable header.
//
// Why not simply CHECK-NOT the bare <ostream>/<istream> paths in the -MD list?
// Because on old libstdc++ (e.g. gcc 8) <iterator> unconditionally pulls in
// <ostream>/<istream> to define std::ostream_iterator/istream_iterator, and
// the KHR surface legitimately uses <iterator> (via sycl/multi_ptr.hpp).
// Newer libstdc++ and libc++ do not. So a bare-path check both false-fails on
// old toolchains and, being a stdlib artifact, does not actually indicate a
// SYCL header regression. Guard #2 catches the real regression (a raw include
// in our own header) regardless of standard-library version.
//
// <sycl/sycl.hpp> and headers under <sycl/ext/...> are intentionally out of
// scope -- only the KHR set is required to be device-safe today. The OV team
// will interface mainly through the kernel compiler and the KHR headers. As
Expand All @@ -27,12 +51,22 @@
// sycl.hpp from this test.
//
// RUN: %clangxx -fsycl -fsycl-device-only -include %S/Inputs/khr_all.hpp \
// RUN: -c %s -o %t.o -MD -MF - | FileCheck %s
// RUN: -c %s -o %t.o -MD -MF %t.d
//
// Guard 1: no iostream machinery in the dependency graph.
// RUN: FileCheck %s < %t.d
//
// Guard 2: no raw stream #include in any KHR-reachable SYCL header. Extract the
// SYCL header paths from the -MD list and grep their sources. `not` wraps the
// inner grep so the pipeline fails iff a stream include is found; `xargs -r`
// avoids running grep on an empty header list.
// RUN: grep -oE '[^ ]*/include/sycl/[^ ]*\.hpp' %t.d \
// RUN: | xargs -r not grep -HnE '^[[:space:]]*#[[:space:]]*include[[:space:]]*<(iostream|istream|ostream|sstream)>'
//
// REQUIRES: linux
//
// CHECK-NOT: iostream_proxy.hpp
// CHECK-NOT: {{/iostream[ \\]}}
// CHECK-NOT: {{/ostream[ \\]}}
// CHECK-NOT: {{/istream[ \\]}}
// CHECK-NOT: {{/iostream\.h}}
// CHECK-NOT: {{/ostream\.h}}
// CHECK-NOT: {{/istream\.h}}
Loading