Skip to content

Commit 0119913

Browse files
committed
[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 <serguei.n.dmitriev@intel.com>
1 parent 1fe5eaa commit 0119913

File tree

1 file changed

+93
-18
lines changed

1 file changed

+93
-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
}

0 commit comments

Comments
 (0)