Skip to content

Commit e767401

Browse files
authored
[SYCL][ESIMD] Add semi-dynamic SLM allocation - esimd::experimental::slm_allocator. (#7759)
This patch adds new class - slm_allocator - and its lowering. This is RAII-style class used to implement "semi-dynamic" SLM allocation. SLM is allocated in the constructor and released in the destructor, that's why it is "dynamic", as opposed to fully static allocation style of 'slm_init'. Actual offset of SLM chunk allocated by the call is calculated at compile time, that's why it is "semi-". To calculate SLM usage by a kernel, compiler finds a path in a callgraph with the largest amount of SLM "locked" by slm_allocator objects live along the paths. slm_init call also participates in calculating SLM budget. It can be modelled as slm_allocator object declared at the very beginning of a kernel and live till its the very end. Since a call graph is used, function pointers and recursion is not supported. Complementary E2E test: intel/llvm-test-suite#1449. Signed-off-by: Konstantin S Bobrovsky <[email protected]>
1 parent d236207 commit e767401

File tree

14 files changed

+1033
-295
lines changed

14 files changed

+1033
-295
lines changed

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

Lines changed: 40 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
// Utility functions for processing ESIMD code.
99
//===----------------------------------------------------------------------===//
1010

11+
#pragma once
12+
13+
#include "llvm/GenXIntrinsics/GenXMetadata.h"
14+
1115
#include "llvm/ADT/SmallPtrSet.h"
1216
#include "llvm/ADT/SmallVector.h"
1317
#include "llvm/Demangle/ItaniumDemangle.h"
@@ -17,7 +21,7 @@ namespace llvm {
1721
namespace esimd {
1822

1923
constexpr char ESIMD_MARKER_MD[] = "sycl_explicit_simd";
20-
// This is the prefixes of the names generated from
24+
constexpr char GENX_KERNEL_METADATA[] = "genx.kernels";
2125
// sycl/ext/oneapi/experimental/invoke_simd.hpp::__builtin_invoke_simd
2226
// overloads instantiations:
2327
constexpr char INVOKE_SIMD_PREF[] = "_Z33__regcall3____builtin_invoke_simd";
@@ -39,37 +43,6 @@ inline void assert_and_diag(bool Condition, StringRef Msg,
3943
}
4044
}
4145

42-
/// Tells if this value is a bit cast or address space cast.
43-
bool isCast(const Value *V);
44-
45-
/// Tells if this value is a GEP instructions with all zero indices.
46-
bool isZeroGEP(const Value *V);
47-
48-
/// Climbs up the use-def chain of given value until a value which is not a
49-
/// bit cast or address space cast is met.
50-
const Value *stripCasts(const Value *V);
51-
Value *stripCasts(Value *V);
52-
53-
/// Climbs up the use-def chain of given value until a value is met which is
54-
/// neither of:
55-
/// - bit cast
56-
/// - address space cast
57-
/// - GEP instruction with all zero indices
58-
const Value *stripCastsAndZeroGEPs(const Value *V);
59-
Value *stripCastsAndZeroGEPs(Value *V);
60-
61-
/// Collects uses of given value "looking through" casts. I.e. if a use is a
62-
/// cast (chain), then uses of the result of the cast (chain) are collected.
63-
void collectUsesLookThroughCasts(const Value *V,
64-
SmallPtrSetImpl<const Use *> &Uses);
65-
66-
/// Collects uses of given pointer-typed value "looking through" casts and GEPs
67-
/// with all zero indices - those pointer transformation instructions which
68-
/// don't change pointed-to value. E.g. if a use is a cast (chain), then uses of
69-
/// the result of the cast (chain) are collected.
70-
void collectUsesLookThroughCastsAndZeroGEPs(const Value *V,
71-
SmallPtrSetImpl<const Use *> &Uses);
72-
7346
/// Unwraps a presumably simd* type to extract the native vector type encoded
7447
/// in it. Returns nullptr if failed to do so.
7548
Type *getVectorTyOrNull(StructType *STy);
@@ -104,5 +77,40 @@ class SimpleAllocator {
10477
~SimpleAllocator() { reset(); }
10578
};
10679

80+
// Turn a MDNode into llvm::value or its subclass.
81+
// Return nullptr if the underlying value has type mismatch.
82+
template <typename Ty = llvm::Value> Ty *getValue(llvm::Metadata *M) {
83+
if (auto VM = dyn_cast<llvm::ValueAsMetadata>(M))
84+
if (auto V = dyn_cast<Ty>(VM->getValue()))
85+
return V;
86+
return nullptr;
87+
}
88+
89+
// Turn given Value into metadata.
90+
inline llvm::Metadata *getMetadata(llvm::Value *V) {
91+
return llvm::ValueAsMetadata::get(V);
92+
}
93+
94+
// A functor which updates ESIMD kernel's uint64_t metadata in case it is less
95+
// than the given one. Used in callgraph traversal to update nbarriers or SLM
96+
// size metadata. Update is performed by the '()' operator and happens only
97+
// when given function matches one of the kernels - thus, only reachable kernels
98+
// are updated.
99+
struct UpdateUint64MetaDataToMaxValue {
100+
Module &M;
101+
// The uint64_t metadata key to update.
102+
genx::KernelMDOp Key;
103+
// The new metadata value. Must be greater than the old for update to happen.
104+
uint64_t NewVal;
105+
// Pre-selected nodes from GENX_KERNEL_METADATA which can only potentially be
106+
// updated.
107+
SmallVector<MDNode *, 4> CandidatesToUpdate;
108+
109+
UpdateUint64MetaDataToMaxValue(Module &M, genx::KernelMDOp Key,
110+
uint64_t NewVal);
111+
112+
void operator()(Function *F) const;
113+
};
114+
107115
} // namespace esimd
108116
} // namespace llvm

llvm/include/llvm/SYCLLowerIR/ESIMD/LowerESIMD.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,10 @@ class ESIMDOptimizeVecArgCallConvPass
8080
PreservedAnalyses run(Module &M, ModuleAnalysisManager &);
8181
};
8282

83+
// Lowers calls __esimd_slm_alloc, __esimd_slm_free and __esimd_slm_init APIs.
84+
// See more details in the .cpp file.
85+
size_t lowerSLMReservationCalls(Module &M);
86+
8387
// Lowers calls to __esimd_set_kernel_properties
8488
class SYCLLowerESIMDKernelPropsPass
8589
: public PassInfoMixin<SYCLLowerESIMDKernelPropsPass> {

llvm/include/llvm/SYCLLowerIR/SYCLUtils.h

Lines changed: 55 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
//===------------ SYCLUtils.h - SYCL utility functions
2-
//------------------===//
1+
//===------------ SYCLUtils.h - 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,14 +9,20 @@
109
//===----------------------------------------------------------------------===//
1110
#pragma once
1211

12+
#include "llvm/ADT/STLExtras.h"
1313
#include "llvm/ADT/SmallPtrSet.h"
1414
#include "llvm/IR/Function.h"
15+
#include "llvm/IR/Instructions.h"
16+
#include "llvm/IR/Operator.h"
1517

1618
#include <functional>
19+
1720
namespace llvm {
1821
namespace sycl {
1922
namespace utils {
20-
using CallGraphNodeAction = std::function<void(Function *)>;
23+
constexpr char ATTR_SYCL_MODULE_ID[] = "sycl-module-id";
24+
25+
using CallGraphNodeAction = ::std::function<void(Function *)>;
2126
using CallGraphFunctionFilter =
2227
std::function<bool(const Instruction *, const Function *)>;
2328

@@ -63,6 +68,53 @@ void traverseCallgraphUp(
6368
traverseCallgraphUp(F, CallGraphNodeAction(ActionF), Visited,
6469
ErrorOnNonCallUse, functionFilter);
6570
}
71+
72+
/// Tells if this value is a bit cast or address space cast.
73+
bool isCast(const Value *V);
74+
75+
/// Tells if this value is a GEP instructions with all zero indices.
76+
bool isZeroGEP(const Value *V);
77+
78+
/// Climbs up the use-def chain of given value until a value which is not a
79+
/// bit cast or address space cast is met.
80+
const Value *stripCasts(const Value *V);
81+
Value *stripCasts(Value *V);
82+
83+
/// Climbs up the use-def chain of given value until a value is met which is
84+
/// neither of:
85+
/// - bit cast
86+
/// - address space cast
87+
/// - GEP instruction with all zero indices
88+
const Value *stripCastsAndZeroGEPs(const Value *V);
89+
Value *stripCastsAndZeroGEPs(Value *V);
90+
91+
/// Collects uses of given value "looking through" casts. I.e. if a use is a
92+
/// cast (chain), then uses of the result of the cast (chain) are collected.
93+
void collectUsesLookThroughCasts(const Value *V,
94+
SmallPtrSetImpl<const Use *> &Uses);
95+
96+
/// Collects uses of given pointer-typed value "looking through" casts and GEPs
97+
/// with all zero indices - those pointer transformation instructions which
98+
/// don't change pointed-to value. E.g. if a use is a cast (chain), then uses of
99+
/// the result of the cast (chain) are collected.
100+
void collectUsesLookThroughCastsAndZeroGEPs(const Value *V,
101+
SmallPtrSetImpl<const Use *> &Uses);
102+
103+
void collectUsesLookThroughCasts(const Value *V,
104+
SmallPtrSetImpl<const Use *> &Uses);
105+
106+
void collectUsesLookThroughCastsAndZeroGEPs(const Value *V,
107+
SmallPtrSetImpl<const Use *> &Uses);
108+
109+
bool collectPossibleStoredVals(
110+
Value *Addr, SmallPtrSetImpl<Value *> &Vals,
111+
std::function<bool(const CallInst *)> EscapesIfAddrIsArgOf =
112+
[](const CallInst *) { return true; });
113+
114+
inline bool isSYCLExternalFunction(const Function *F) {
115+
return F->hasFnAttribute(ATTR_SYCL_MODULE_ID);
116+
}
117+
66118
} // namespace utils
67119
} // namespace sycl
68120
} // namespace llvm

llvm/lib/SYCLLowerIR/CMakeLists.txt

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,17 +47,18 @@ set_property(GLOBAL PROPERTY LLVMGenXIntrinsics_SOURCE_PROP ${LLVMGenXIntrinsics
4747
set_property(GLOBAL PROPERTY LLVMGenXIntrinsics_BINARY_PROP ${LLVMGenXIntrinsics_BINARY_DIR})
4848

4949
add_llvm_component_library(LLVMSYCLLowerIR
50-
ESIMD/LowerESIMD.cpp
51-
ESIMD/LowerESIMDVLoadVStore.cpp
52-
ESIMD/LowerESIMDVecArg.cpp
50+
ESIMD/ESIMDOptimizeVecArgCallConv.cpp
5351
ESIMD/ESIMDUtils.cpp
5452
ESIMD/ESIMDVerifier.cpp
53+
ESIMD/LowerESIMD.cpp
5554
ESIMD/LowerESIMDKernelAttrs.cpp
56-
ESIMD/ESIMDOptimizeVecArgCallConv.cpp
55+
ESIMD/LowerESIMDVecArg.cpp
56+
ESIMD/LowerESIMDVLoadVStore.cpp
57+
ESIMD/LowerESIMDSlmReservation.cpp
5758
LowerInvokeSimd.cpp
5859
LowerKernelProps.cpp
59-
LowerWGScope.cpp
6060
LowerWGLocalMemory.cpp
61+
LowerWGScope.cpp
6162
MutatePrintfAddrspace.cpp
6263
SYCLPropagateAspectsUsage.cpp
6364
SYCLUtils.cpp

llvm/lib/SYCLLowerIR/ESIMD/ESIMDOptimizeVecArgCallConv.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
#include "llvm/SYCLLowerIR/ESIMD/ESIMDUtils.h"
2121
#include "llvm/SYCLLowerIR/ESIMD/LowerESIMD.h"
22+
#include "llvm/SYCLLowerIR/SYCLUtils.h"
2223

2324
#include "llvm/GenXIntrinsics/GenXIntrinsics.h"
2425

@@ -76,7 +77,7 @@ getMemTypeIfSameAddressLoadsStores(SmallPtrSetImpl<const Use *> &Uses,
7677
if (Uses.size() == 0) {
7778
return nullptr;
7879
}
79-
Value *Addr = esimd::stripCastsAndZeroGEPs((*Uses.begin())->get());
80+
Value *Addr = sycl::utils::stripCastsAndZeroGEPs((*Uses.begin())->get());
8081

8182
for (const auto *UU : Uses) {
8283
const User *U = UU->getUser();
@@ -92,7 +93,7 @@ getMemTypeIfSameAddressLoadsStores(SmallPtrSetImpl<const Use *> &Uses,
9293
}
9394

9495
if (const auto *SI = dyn_cast<StoreInst>(U)) {
95-
if (esimd::stripCastsAndZeroGEPs(SI->getPointerOperand()) != Addr) {
96+
if (sycl::utils::stripCastsAndZeroGEPs(SI->getPointerOperand()) != Addr) {
9697
// the pointer escapes into memory
9798
return nullptr;
9899
}
@@ -167,7 +168,7 @@ Type *getPointedToTypeIfOptimizeable(const Argument &FormalParam) {
167168
// }
168169
{
169170
SmallPtrSet<const Use *, 4> Uses;
170-
esimd::collectUsesLookThroughCastsAndZeroGEPs(&FormalParam, Uses);
171+
sycl::utils::collectUsesLookThroughCastsAndZeroGEPs(&FormalParam, Uses);
171172
bool LoadMet = 0;
172173
bool StoreMet = 0;
173174
ContentT = getMemTypeIfSameAddressLoadsStores(Uses, LoadMet, StoreMet);
@@ -225,14 +226,14 @@ Type *getPointedToTypeIfOptimizeable(const Argument &FormalParam) {
225226
if (!Call || (Call->getCalledFunction() != F)) {
226227
return nullptr;
227228
}
228-
Value *ActualParam = esimd::stripCastsAndZeroGEPs(
229+
Value *ActualParam = sycl::utils::stripCastsAndZeroGEPs(
229230
Call->getArgOperand(FormalParam.getArgNo()));
230231

231232
if (!IsSret && !isa<AllocaInst>(ActualParam)) {
232233
return nullptr;
233234
}
234235
SmallPtrSet<const Use *, 4> Uses;
235-
esimd::collectUsesLookThroughCastsAndZeroGEPs(ActualParam, Uses);
236+
sycl::utils::collectUsesLookThroughCastsAndZeroGEPs(ActualParam, Uses);
236237
bool LoadMet = 0;
237238
bool StoreMet = 0;
238239

0 commit comments

Comments
 (0)