Skip to content

Commit 1fa24a1

Browse files
committed
Add checks to prevent use of slm_init in functions called using invoke_simd
1 parent 5edbbd5 commit 1fa24a1

File tree

2 files changed

+53
-6
lines changed

2 files changed

+53
-6
lines changed

llvm/lib/SYCLLowerIR/ESIMD/LowerESIMD.cpp

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1754,14 +1754,11 @@ static void checkSLMInit(Module &M) {
17541754
SmallPtrSet<const Function *, 8u> Callers;
17551755
for (auto &F : M) {
17561756
if (isSlmInit(F)) {
1757-
auto filterInvokeSimdUse = [](const Instruction *, const Function *) {
1758-
return false;
1759-
};
17601757
for (User *U : F.users()) {
17611758
auto *FCall = dyn_cast<CallInst>(U);
17621759
if (FCall && FCall->getCalledFunction() == &F) {
17631760
Function *GenF = FCall->getFunction();
1764-
1761+
SmallPtrSet<Function *, 32> Visited;
17651762
sycl::utils::traverseCallgraphUp(
17661763
GenF,
17671764
[&](Function *GraphNode) {
@@ -1778,7 +1775,21 @@ static void checkSLMInit(Module &M) {
17781775
}
17791776
}
17801777
},
1781-
false, filterInvokeSimdUse);
1778+
Visited, false);
1779+
bool VisitedKernel = false;
1780+
for (const Function *Caller : Visited) {
1781+
if (llvm::esimd::isESIMDKernel(*Caller)) {
1782+
VisitedKernel = true;
1783+
break;
1784+
}
1785+
}
1786+
if (!VisitedKernel) {
1787+
F.getContext().emitError(
1788+
"slm_init must be called directly from ESIMD kernel.");
1789+
}
1790+
} else {
1791+
F.getContext().emitError(
1792+
"slm_init can only be used as a direct call.");
17821793
}
17831794
}
17841795
}
@@ -1886,7 +1897,7 @@ bool SYCLLowerESIMDPass::prepareForAlwaysInliner(Module &M) {
18861897
if (FCall && FCall->getCalledFunction() == &F) {
18871898
Function *GenF = FCall->getFunction();
18881899
// The original kernel (UserK) if often automatically separated into
1889-
// a spir_func (GenF) that is then cal led from spir_kernel (GenK).
1900+
// a spir_func (GenF) that is then called from spir_kernel (GenK).
18901901
// When that happens, the calls of slm_init<N>() originally placed
18911902
// in 'UserK' get moved to spir_func 'GenF', which creates wrong IR
18921903
// because slm_init() must be called only from a kernel.
@@ -1943,8 +1954,10 @@ static void fixFunctionReadWriteAttributes(Module &M) {
19431954

19441955
PreservedAnalyses SYCLLowerESIMDPass::run(Module &M,
19451956
ModuleAnalysisManager &MAM) {
1957+
19461958
// Check validity of slm_init calls.
19471959
checkSLMInit(M);
1960+
19481961
// AlwaysInlinerPass is required for correctness.
19491962
bool ForceInline = prepareForAlwaysInliner(M);
19501963
if (ForceInline) {
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// This test verifies call to slm_init from a function called through
2+
// invoke_simd triggers an error.
3+
4+
// RUN: not %clangxx -fsycl -fno-sycl-device-code-split-esimd -Xclang -fsycl-allow-func-ptr %s 2>&1 | FileCheck %s
5+
6+
#include <sycl/ext/intel/esimd.hpp>
7+
#include <sycl/ext/oneapi/experimental/invoke_simd.hpp>
8+
#include <sycl/ext/oneapi/experimental/uniform.hpp>
9+
#include <sycl/sycl.hpp>
10+
11+
#include <functional>
12+
#include <iostream>
13+
#include <type_traits>
14+
15+
using namespace sycl::ext::oneapi::experimental;
16+
using namespace sycl;
17+
namespace esimd = sycl::ext::intel::esimd;
18+
19+
SYCL_EXTERNAL
20+
[[intel::device_indirectly_callable]] void __regcall SIMD_CALLEE_VOID()
21+
SYCL_ESIMD_FUNCTION {
22+
esimd::slm_init<1024>();
23+
}
24+
25+
int main() {
26+
queue Q;
27+
nd_range<1> NDR{range<1>{2}, range<1>{2}};
28+
Q.parallel_for(NDR, [=](nd_item<1> NDI) [[intel::reqd_sub_group_size(16)]] {
29+
sub_group sg = NDI.get_sub_group();
30+
invoke_simd(sg, SIMD_CALLEE_VOID);
31+
}).wait();
32+
return 0;
33+
}
34+
// CHECK: slm_init must be called directly from ESIMD kernel.

0 commit comments

Comments
 (0)