Skip to content

Commit eaf8b42

Browse files
authored
[SYCL][ESIMD] Change esimd-verifier logic for detecting valid SYCL calls (#5914)
* [SYCL][ESIMD] Change esimd-verifier logic for detecting valid SYCL calls Instead of having a list invalid cl::sycl::* function esimd-verifier now has a list of valid cl::sycl::* functions that are allowed for use in ESIMD context. All other SYCL functions are considered invalid. Signed-off-by: Sergey Dmitriev <[email protected]>
1 parent 0b456ce commit eaf8b42

File tree

2 files changed

+102
-18
lines changed

2 files changed

+102
-18
lines changed

llvm/lib/SYCLLowerIR/ESIMD/ESIMDVerifier.cpp

Lines changed: 93 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
#include "llvm/SYCLLowerIR/ESIMD/ESIMDVerifier.h"
1515
#include "llvm/Demangle/Demangle.h"
16+
#include "llvm/Demangle/ItaniumDemangle.h"
1617
#include "llvm/IR/InstIterator.h"
1718
#include "llvm/IR/Instructions.h"
1819
#include "llvm/IR/Module.h"
@@ -22,17 +23,64 @@
2223
#include "llvm/Support/Regex.h"
2324

2425
using namespace llvm;
26+
namespace id = itanium_demangle;
2527

2628
#define DEBUG_TYPE "esimd-verifier"
2729

28-
// A list of unsupported functions in ESIMD context.
29-
static const char *IllegalFunctions[] = {
30-
"^cl::sycl::multi_ptr<.+> cl::sycl::accessor<.+>::get_pointer<.+>\\(\\) "
31-
"const",
32-
" cl::sycl::accessor<.+>::operator\\[\\]<.+>\\(.+\\) const"};
30+
// A list of SYCL functions (regexps) allowed for use in ESIMD context.
31+
static const char *LegalSYCLFunctions[] = {
32+
"^cl::sycl::accessor<.+>::accessor",
33+
"^cl::sycl::accessor<.+>::~accessor",
34+
"^cl::sycl::accessor<.+>::getNativeImageObj",
35+
"^cl::sycl::accessor<.+>::__init_esimd",
36+
"^cl::sycl::id<.+>::.+",
37+
"^cl::sycl::item<.+>::.+",
38+
"^cl::sycl::nd_item<.+>::.+",
39+
"^cl::sycl::group<.+>::.+",
40+
"^cl::sycl::sub_group<.+>::.+",
41+
"^cl::sycl::range<.+>::.+",
42+
"^cl::sycl::kernel_handler::.+",
43+
"^cl::sycl::cos<.+>",
44+
"^cl::sycl::sin<.+>",
45+
"^cl::sycl::log<.+>",
46+
"^cl::sycl::exp<.+>",
47+
"^cl::sycl::operator.+<.+>",
48+
"^cl::sycl::ext::oneapi::sub_group::.+",
49+
"^cl::sycl::ext::oneapi::experimental::spec_constant<.+>::.+",
50+
"^cl::sycl::ext::oneapi::experimental::this_sub_group"};
3351

3452
namespace {
3553

54+
// Simplest possible implementation of an allocator for the Itanium demangler
55+
class SimpleAllocator {
56+
protected:
57+
SmallVector<void *, 128> Ptrs;
58+
59+
public:
60+
void reset() {
61+
for (void *Ptr : Ptrs) {
62+
// Destructors are not called, but that is OK for the
63+
// itanium_demangle::Node subclasses
64+
std::free(Ptr);
65+
}
66+
Ptrs.resize(0);
67+
}
68+
69+
template <typename T, typename... Args> T *makeNode(Args &&...args) {
70+
void *Ptr = std::calloc(1, sizeof(T));
71+
Ptrs.push_back(Ptr);
72+
return new (Ptr) T(std::forward<Args>(args)...);
73+
}
74+
75+
void *allocateNodeArray(size_t sz) {
76+
void *Ptr = std::calloc(sz, sizeof(id::Node *));
77+
Ptrs.push_back(Ptr);
78+
return Ptr;
79+
}
80+
81+
~SimpleAllocator() { reset(); }
82+
};
83+
3684
class ESIMDVerifierImpl {
3785
const Module &M;
3886

@@ -63,22 +111,49 @@ class ESIMDVerifierImpl {
63111
if (!Callee)
64112
continue;
65113

66-
// Demangle called function name and check if it matches any illegal
67-
// function name. Report an error if there is a match.
68-
std::string DemangledName = demangle(Callee->getName().str());
69-
for (const char *Name : IllegalFunctions) {
70-
Regex NameRE(Name);
71-
assert(NameRE.isValid() && "invalid function name regex");
72-
if (NameRE.match(DemangledName)) {
73-
std::string ErrorMsg = std::string("function '") + DemangledName +
74-
"' is not supported in ESIMD context";
75-
F->getContext().emitError(&I, ErrorMsg);
76-
}
77-
}
78-
79114
// Add callee to the list to be analyzed if it is not a declaration.
80115
if (!Callee->isDeclaration())
81116
Add2Worklist(Callee);
117+
118+
// Demangle called function name and check if it is legal to use this
119+
// function in ESIMD context.
120+
StringRef MangledName = Callee->getName();
121+
id::ManglingParser<SimpleAllocator> Parser(MangledName.begin(),
122+
MangledName.end());
123+
id::Node *AST = Parser.parse();
124+
if (!AST || AST->getKind() != id::Node::KFunctionEncoding)
125+
continue;
126+
127+
auto *FE = static_cast<id::FunctionEncoding *>(AST);
128+
const id::Node *NameNode = FE->getName();
129+
if (!NameNode) // Can it be null?
130+
continue;
131+
132+
id::OutputBuffer NameBuf;
133+
NameNode->print(NameBuf);
134+
StringRef Name(NameBuf.getBuffer(), NameBuf.getCurrentPosition());
135+
136+
// We are interested in functions defined in SYCL namespace, but
137+
// outside of ESIMD namespaces.
138+
if (!Name.startswith("cl::sycl::") ||
139+
Name.startswith("cl::sycl::detail::") ||
140+
Name.startswith("cl::sycl::ext::intel::esimd::") ||
141+
Name.startswith("cl::sycl::ext::intel::experimental::esimd::"))
142+
continue;
143+
144+
// Check if function name matches any allowed SYCL function name.
145+
if (any_of(LegalSYCLFunctions, [Name](const char *LegalName) {
146+
Regex LegalNameRE(LegalName);
147+
assert(LegalNameRE.isValid() && "invalid function name regex");
148+
return LegalNameRE.match(Name);
149+
}))
150+
continue;
151+
152+
// If not, report an error.
153+
std::string ErrorMsg = std::string("function '") +
154+
demangle(MangledName.str()) +
155+
"' is not supported in ESIMD context";
156+
F->getContext().emitError(&I, ErrorMsg);
82157
}
83158
}
84159
}

sycl/test/esimd/esimd_verify.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@
33
// RUN: not %clangxx -fsycl -fsycl-device-only -flegacy-pass-manager -O0 -S %s -o /dev/null 2>&1 | FileCheck %s
44
// RUN: not %clangxx -fsycl -fsycl-device-only -fno-legacy-pass-manager -O0 -S %s -o /dev/null 2>&1 | FileCheck %s
55

6+
#include <CL/sycl.hpp>
67
#include <sycl/ext/intel/esimd.hpp>
78

89
using namespace cl::sycl;
910
using namespace sycl::ext::intel::esimd;
1011

1112
// CHECK-DAG: error: function 'cl::sycl::multi_ptr<{{.+}}> cl::sycl::accessor<{{.+}}>::get_pointer<{{.+}}>() const' is not supported in ESIMD context
1213
// CHECK-DAG: error: function '{{.+}} cl::sycl::accessor<{{.+}}>::operator[]<{{.+}}>({{.+}}) const' is not supported in ESIMD context
14+
// CHECK-DAG: error: function 'cl::sycl::ext::oneapi::detail::reducer<int, std::plus<int>, void>::combine(int const&)' is not supported in ESIMD context
1315

1416
SYCL_EXTERNAL auto
1517
test(accessor<int, 1, access::mode::read_write, access::target::device> &acc)
@@ -22,3 +24,10 @@ test1(accessor<int, 1, access::mode::read_write, access::target::device> &acc)
2224
SYCL_ESIMD_FUNCTION {
2325
acc[0] = 0;
2426
}
27+
28+
void test2(sycl::handler &cgh, int *buf) {
29+
auto reduction = sycl::reduction(buf, sycl::plus<int>());
30+
cgh.parallel_for<class Test2>(sycl::range<1>(1), reduction,
31+
[=](sycl::id<1>, auto &reducer)
32+
SYCL_ESIMD_KERNEL { reducer.combine(15); });
33+
}

0 commit comments

Comments
 (0)