Skip to content

Commit 4d3c150

Browse files
fineg74kbobrovs
andauthored
[SYCL][ESIMD]Limit propagation of ESIMD attributes (#7191)
Co-authored-by: kbobrovs <[email protected]>
1 parent 56c4116 commit 4d3c150

File tree

7 files changed

+91
-82
lines changed

7 files changed

+91
-82
lines changed

llvm/include/llvm/SYCLLowerIR/ESIMD/ESIMDUtils.h

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,18 @@
99
//===----------------------------------------------------------------------===//
1010

1111
#include "llvm/ADT/SmallPtrSet.h"
12+
#include "llvm/ADT/SmallVector.h"
13+
#include "llvm/Demangle/ItaniumDemangle.h"
1214
#include "llvm/IR/Function.h"
1315

1416
namespace llvm {
1517
namespace esimd {
1618

1719
constexpr char ESIMD_MARKER_MD[] = "sycl_explicit_simd";
20+
// This is the prefixes of the names generated from
21+
// sycl/ext/oneapi/experimental/invoke_simd.hpp::__builtin_invoke_simd
22+
// overloads instantiations:
23+
constexpr char INVOKE_SIMD_PREF[] = "_Z33__regcall3____builtin_invoke_simd";
1824

1925
// Tells whether given function is a ESIMD kernel.
2026
bool isESIMDKernel(const Function &F);
@@ -68,5 +74,35 @@ void collectUsesLookThroughCastsAndZeroGEPs(const Value *V,
6874
/// in it. Returns nullptr if failed to do so.
6975
Type *getVectorTyOrNull(StructType *STy);
7076

77+
// Simplest possible implementation of an allocator for the Itanium demangler
78+
class SimpleAllocator {
79+
protected:
80+
SmallVector<void *, 128> Ptrs;
81+
82+
public:
83+
void reset() {
84+
for (void *Ptr : Ptrs) {
85+
// Destructors are not called, but that is OK for the
86+
// itanium_demangle::Node subclasses
87+
std::free(Ptr);
88+
}
89+
Ptrs.resize(0);
90+
}
91+
92+
template <typename T, typename... Args> T *makeNode(Args &&...args) {
93+
void *Ptr = std::calloc(1, sizeof(T));
94+
Ptrs.push_back(Ptr);
95+
return new (Ptr) T(std::forward<Args>(args)...);
96+
}
97+
98+
void *allocateNodeArray(size_t sz) {
99+
void *Ptr = std::calloc(sz, sizeof(itanium_demangle::Node *));
100+
Ptrs.push_back(Ptr);
101+
return Ptr;
102+
}
103+
104+
~SimpleAllocator() { reset(); }
105+
};
106+
71107
} // namespace esimd
72108
} // namespace llvm

llvm/include/llvm/SYCLLowerIR/SYCLUtils.h

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,32 +18,50 @@ namespace llvm {
1818
namespace sycl {
1919
namespace utils {
2020
using CallGraphNodeAction = std::function<void(Function *)>;
21+
using CallGraphFunctionFilter =
22+
std::function<bool(const Instruction *, const Function *)>;
2123

2224
// Traverses call graph starting from given function up the call chain applying
2325
// given action to each function met on the way. If \c ErrorOnNonCallUse
2426
// parameter is true, then no functions' uses are allowed except calls.
2527
// Otherwise, any function where use of the current one happened is added to the
2628
// call graph as if the use was a call.
29+
// The 'functionFilter' parameter is a callback function that can be used to
30+
// control which functions will be added to a call graph.
31+
//
32+
// The callback is invoked whenever a function being traversed is used
33+
// by some instruction which is not a call to this instruction (e.g. storing
34+
// function pointer to memory) - the first parameter is the using instructions,
35+
// the second - the function being traversed. The parent function of the
36+
// instruction is added to the call graph depending on whether the callback
37+
// returns 'true' (added) or 'false' (not added).
2738
// Functions which are part of the visited set ('Visited' parameter) are not
2839
// traversed.
29-
void traverseCallgraphUp(llvm::Function *F, CallGraphNodeAction NodeF,
30-
SmallPtrSetImpl<Function *> &Visited,
31-
bool ErrorOnNonCallUse);
40+
41+
void traverseCallgraphUp(
42+
llvm::Function *F, CallGraphNodeAction NodeF,
43+
SmallPtrSetImpl<Function *> &Visited, bool ErrorOnNonCallUse,
44+
const CallGraphFunctionFilter &functionFilter =
45+
[](const Instruction *, const Function *) { return true; });
3246

3347
template <class CallGraphNodeActionF>
34-
void traverseCallgraphUp(Function *F, CallGraphNodeActionF ActionF,
35-
SmallPtrSetImpl<Function *> &Visited,
36-
bool ErrorOnNonCallUse) {
48+
void traverseCallgraphUp(
49+
Function *F, CallGraphNodeActionF ActionF,
50+
SmallPtrSetImpl<Function *> &Visited, bool ErrorOnNonCallUse,
51+
const CallGraphFunctionFilter &functionFilter =
52+
[](const Instruction *, const Function *) { return true; }) {
3753
traverseCallgraphUp(F, CallGraphNodeAction(ActionF), Visited,
38-
ErrorOnNonCallUse);
54+
ErrorOnNonCallUse, functionFilter);
3955
}
4056

4157
template <class CallGraphNodeActionF>
42-
void traverseCallgraphUp(Function *F, CallGraphNodeActionF ActionF,
43-
bool ErrorOnNonCallUse = true) {
58+
void traverseCallgraphUp(
59+
Function *F, CallGraphNodeActionF ActionF, bool ErrorOnNonCallUse = true,
60+
const CallGraphFunctionFilter &functionFilter =
61+
[](const Instruction *, const Function *) { return true; }) {
4462
SmallPtrSet<Function *, 32> Visited;
4563
traverseCallgraphUp(F, CallGraphNodeAction(ActionF), Visited,
46-
ErrorOnNonCallUse);
64+
ErrorOnNonCallUse, functionFilter);
4765
}
4866
} // namespace utils
4967
} // namespace sycl

llvm/lib/SYCLLowerIR/ESIMD/ESIMDVerifier.cpp

Lines changed: 2 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,13 @@
1919
#include "llvm/IR/Module.h"
2020
#include "llvm/InitializePasses.h"
2121
#include "llvm/Pass.h"
22+
#include "llvm/SYCLLowerIR/ESIMD/ESIMDUtils.h"
2223
#include "llvm/Support/CommandLine.h"
2324
#include "llvm/Support/Debug.h"
2425
#include "llvm/Support/Regex.h"
2526

2627
using namespace llvm;
28+
using namespace llvm::esimd;
2729
namespace id = itanium_demangle;
2830

2931
#define DEBUG_TYPE "esimd-verifier"
@@ -64,36 +66,6 @@ static const char *LegalSYCLFunctionsInStatelessMode[] = {
6466

6567
namespace {
6668

67-
// Simplest possible implementation of an allocator for the Itanium demangler
68-
class SimpleAllocator {
69-
protected:
70-
SmallVector<void *, 128> Ptrs;
71-
72-
public:
73-
void reset() {
74-
for (void *Ptr : Ptrs) {
75-
// Destructors are not called, but that is OK for the
76-
// itanium_demangle::Node subclasses
77-
std::free(Ptr);
78-
}
79-
Ptrs.resize(0);
80-
}
81-
82-
template <typename T, typename... Args> T *makeNode(Args &&...args) {
83-
void *Ptr = std::calloc(1, sizeof(T));
84-
Ptrs.push_back(Ptr);
85-
return new (Ptr) T(std::forward<Args>(args)...);
86-
}
87-
88-
void *allocateNodeArray(size_t sz) {
89-
void *Ptr = std::calloc(sz, sizeof(id::Node *));
90-
Ptrs.push_back(Ptr);
91-
return Ptr;
92-
}
93-
94-
~SimpleAllocator() { reset(); }
95-
};
96-
9769
class ESIMDVerifierImpl {
9870
const Module &M;
9971
bool ForceStatelessMem;

llvm/lib/SYCLLowerIR/ESIMD/LowerESIMD.cpp

Lines changed: 1 addition & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242

4343
using namespace llvm;
4444
namespace id = itanium_demangle;
45+
using namespace llvm::esimd;
4546

4647
#define DEBUG_TYPE "lower-esimd"
4748

@@ -679,36 +680,6 @@ static const ESIMDIntrinDesc &getIntrinDesc(StringRef SrcSpelling) {
679680
return It->second;
680681
}
681682

682-
// Simplest possible implementation of an allocator for the Itanium demangler
683-
class SimpleAllocator {
684-
protected:
685-
SmallVector<void *, 128> Ptrs;
686-
687-
public:
688-
void reset() {
689-
for (void *Ptr : Ptrs) {
690-
// Destructors are not called, but that is OK for the
691-
// itanium_demangle::Node subclasses
692-
std::free(Ptr);
693-
}
694-
Ptrs.resize(0);
695-
}
696-
697-
template <typename T, typename... Args> T *makeNode(Args &&...args) {
698-
void *Ptr = std::calloc(1, sizeof(T));
699-
Ptrs.push_back(Ptr);
700-
return new (Ptr) T(std::forward<Args>(args)...);
701-
}
702-
703-
void *allocateNodeArray(size_t sz) {
704-
void *Ptr = std::calloc(sz, sizeof(id::Node *));
705-
Ptrs.push_back(Ptr);
706-
return Ptr;
707-
}
708-
709-
~SimpleAllocator() { reset(); }
710-
};
711-
712683
Type *parsePrimitiveTypeString(StringRef TyStr, LLVMContext &Ctx) {
713684
return llvm::StringSwitch<Type *>(TyStr)
714685
.Case("bool", IntegerType::getInt1Ty(Ctx))

llvm/lib/SYCLLowerIR/ESIMD/LowerESIMDKernelAttrs.cpp

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,23 @@
1212
#include "llvm/SYCLLowerIR/ESIMD/LowerESIMD.h"
1313
#include "llvm/SYCLLowerIR/SYCLUtils.h"
1414

15-
#include "llvm/IR/Module.h"
16-
#include "llvm/Pass.h"
17-
1815
#define DEBUG_TYPE "LowerESIMDKernelAttrs"
1916

2017
using namespace llvm;
2118

2219
namespace llvm {
20+
21+
// Filter function for graph traversal when propagating ESIMD attribute.
22+
// While traversing the call graph, non-call use of the traversed function is
23+
// not added to the graph. The reason is that it is impossible to gurantee
24+
// correct inference of use of that function, in particular to determine if that
25+
// function is used as an argument for invoke_simd. As a result, any use of
26+
// function pointers requires explicit marking of the functions as
27+
// ESIMD_FUNCTION if needed.
28+
bool filterInvokeSimdUse(const Instruction *I, const Function *F) {
29+
return false;
30+
}
31+
2332
PreservedAnalyses
2433
SYCLFixupESIMDKernelWrapperMDPass::run(Module &M, ModuleAnalysisManager &MAM) {
2534
bool Modified = false;
@@ -37,7 +46,7 @@ SYCLFixupESIMDKernelWrapperMDPass::run(Module &M, ModuleAnalysisManager &MAM) {
3746
Modified = true;
3847
}
3948
},
40-
false);
49+
false, filterInvokeSimdUse);
4150
}
4251
}
4352
return Modified ? PreservedAnalyses::none() : PreservedAnalyses::all();

llvm/lib/SYCLLowerIR/LowerInvokeSimd.cpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ using namespace llvm::esimd;
3939

4040
namespace {
4141

42-
constexpr char ESIMD_MARKER_MD[] = "sycl_explicit_simd";
4342
constexpr char REQD_SUB_GROUP_SIZE_MD[] = "intel_reqd_sub_group_size";
4443

4544
class SYCLLowerInvokeSimdLegacyPass : public ModulePass {
@@ -73,10 +72,6 @@ ModulePass *llvm::createSYCLLowerInvokeSimdPass() {
7372

7473
namespace {
7574
// TODO support lambda and functor overloads
76-
// This is the prefixes of the names generated from
77-
// sycl/ext/oneapi/experimental/invoke_simd.hpp::__builtin_invoke_simd
78-
// overloads instantiations:
79-
constexpr char INVOKE_SIMD_PREF[] = "_Z33__regcall3____builtin_invoke_simd";
8075

8176
using ValueSetImpl = SmallPtrSetImpl<Value *>;
8277
using ValueSet = SmallPtrSet<Value *, 4>;

llvm/lib/SYCLLowerIR/SYCLUtils.cpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
//===------------ SYCLUtils.cpp - SYCL utility functions
2-
//------------------===//
1+
//===------------ SYCLUtils.cpp - SYCL utility functions ------------------===//
32
//
43
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
54
// See https://llvm.org/LICENSE.txt for license information.
@@ -10,13 +9,18 @@
109
//===----------------------------------------------------------------------===//
1110
#include "llvm/SYCLLowerIR/SYCLUtils.h"
1211
#include "llvm/IR/Instructions.h"
12+
#include "llvm/SYCLLowerIR/ESIMD/ESIMDUtils.h"
1313

1414
namespace llvm {
1515
namespace sycl {
1616
namespace utils {
17+
18+
using namespace llvm::esimd;
19+
1720
void traverseCallgraphUp(llvm::Function *F, CallGraphNodeAction ActionF,
1821
SmallPtrSetImpl<Function *> &FunctionsVisited,
19-
bool ErrorOnNonCallUse) {
22+
bool ErrorOnNonCallUse,
23+
const CallGraphFunctionFilter &functionFilter) {
2024
SmallVector<Function *, 32> Worklist;
2125

2226
if (FunctionsVisited.count(F) == 0)
@@ -43,6 +47,10 @@ void traverseCallgraphUp(llvm::Function *F, CallGraphNodeAction ActionF,
4347
} else {
4448
// ... non-call is OK - add using function to the worklist
4549
if (auto *I = dyn_cast<Instruction>(FCall)) {
50+
if (!functionFilter(I, CurF)) {
51+
continue;
52+
}
53+
4654
auto UseF = I->getFunction();
4755

4856
if (FunctionsVisited.count(UseF) == 0) {

0 commit comments

Comments
 (0)