|
13 | 13 |
|
14 | 14 | #include "llvm/SYCLLowerIR/ESIMD/ESIMDVerifier.h"
|
15 | 15 | #include "llvm/Demangle/Demangle.h"
|
| 16 | +#include "llvm/Demangle/ItaniumDemangle.h" |
16 | 17 | #include "llvm/IR/InstIterator.h"
|
17 | 18 | #include "llvm/IR/Instructions.h"
|
18 | 19 | #include "llvm/IR/Module.h"
|
|
22 | 23 | #include "llvm/Support/Regex.h"
|
23 | 24 |
|
24 | 25 | using namespace llvm;
|
| 26 | +namespace id = itanium_demangle; |
25 | 27 |
|
26 | 28 | #define DEBUG_TYPE "esimd-verifier"
|
27 | 29 |
|
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"}; |
33 | 51 |
|
34 | 52 | namespace {
|
35 | 53 |
|
| 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 | + |
36 | 84 | class ESIMDVerifierImpl {
|
37 | 85 | const Module &M;
|
38 | 86 |
|
@@ -63,22 +111,49 @@ class ESIMDVerifierImpl {
|
63 | 111 | if (!Callee)
|
64 | 112 | continue;
|
65 | 113 |
|
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 |
| - |
79 | 114 | // Add callee to the list to be analyzed if it is not a declaration.
|
80 | 115 | if (!Callee->isDeclaration())
|
81 | 116 | 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); |
82 | 157 | }
|
83 | 158 | }
|
84 | 159 | }
|
|
0 commit comments