Skip to content

Commit 16f76ea

Browse files
authored
[SYCL][Fusion][NoSTL] Encode argument descriptor using fixed-size arrays (#12355)
Introduces the `jit_compiler::DynArray` template to represent a fixed-sized-but-dynamically allocated array with an `std::array`-compatible interface. `DynArray` is then used to replace the uses of `std::vector` in the `SYCLArgumentDescriptor` struct. Client code was updated to either determine the number of arguments beforehand, or use dynamically-growable containers to collect the relevant info locally and then copy it over to a `DynArray` instance. *This PR is part of a series of changes to remove uses of STL classes in the kernel fusion interface to prevent ABI issues in the future.* Signed-off-by: Julian Oppermann <[email protected]>
1 parent c5acdff commit 16f76ea

File tree

11 files changed

+191
-75
lines changed

11 files changed

+191
-75
lines changed

sycl-fusion/common/include/DynArray.h

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
//==------------ DynArray.h - Non-STL replacement for std::array -----------==//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef SYCL_FUSION_COMMON_DYNARRAY_H
10+
#define SYCL_FUSION_COMMON_DYNARRAY_H
11+
12+
#include <algorithm>
13+
14+
namespace jit_compiler {
15+
16+
///
17+
/// A fixed-size, dynamically-allocated array, with an interface that is a
18+
/// subset of `std::array`.
19+
template <typename T> class DynArray {
20+
public:
21+
DynArray() = default;
22+
23+
explicit DynArray(size_t Size) { init(Size); }
24+
25+
~DynArray() { deinit(); }
26+
27+
DynArray(const DynArray &Other) {
28+
init(Other.Size);
29+
std::copy(Other.begin(), Other.end(), begin());
30+
}
31+
32+
DynArray &operator=(const DynArray &Other) {
33+
deinit();
34+
init(Other.Size);
35+
std::copy(Other.begin(), Other.end(), begin());
36+
return *this;
37+
}
38+
39+
DynArray(DynArray &&Other) { moveFrom(std::move(Other)); }
40+
41+
DynArray &operator=(DynArray &&Other) {
42+
deinit();
43+
moveFrom(std::move(Other));
44+
return *this;
45+
}
46+
47+
size_t size() const { return Size; }
48+
bool empty() const { return Size == 0; }
49+
50+
const T *begin() const { return Values; }
51+
const T *end() const { return Values + Size; }
52+
T *begin() { return Values; }
53+
T *end() { return Values + Size; }
54+
55+
const T &operator[](int Idx) const { return Values[Idx]; }
56+
T &operator[](int Idx) { return Values[Idx]; }
57+
58+
private:
59+
T *Values = nullptr;
60+
size_t Size = 0;
61+
62+
void init(size_t NewSize) {
63+
if (NewSize == 0)
64+
return;
65+
66+
Values = new T[NewSize];
67+
Size = NewSize;
68+
}
69+
70+
void deinit() {
71+
if (!Values)
72+
return;
73+
74+
delete[] Values;
75+
Values = nullptr;
76+
Size = 0;
77+
}
78+
79+
void moveFrom(DynArray &&Other) {
80+
Values = Other.Values;
81+
Other.Values = nullptr;
82+
Size = Other.Size;
83+
Other.Size = 0;
84+
}
85+
};
86+
87+
} // namespace jit_compiler
88+
89+
#endif // SYCL_FUSION_COMMON_DYNARRAY_H

sycl-fusion/common/include/Kernel.h

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
#ifndef SYCL_FUSION_COMMON_KERNEL_H
1010
#define SYCL_FUSION_COMMON_KERNEL_H
1111

12+
#include "DynArray.h"
13+
1214
#include <algorithm>
1315
#include <array>
1416
#include <cassert>
@@ -118,6 +120,8 @@ struct SYCLKernelAttribute {
118120
AttributeValueList Values;
119121
};
120122

123+
///
124+
/// Encode usage of parameters for the actual kernel function.
121125
enum ArgUsage : uint8_t {
122126
// Used to indicate that an argument is not used by the kernel
123127
Unused = 0,
@@ -132,15 +136,17 @@ enum ArgUsage : uint8_t {
132136
};
133137

134138
///
135-
/// Encode usage of parameters for the actual kernel function.
136-
using ArgUsageMask = std::vector<std::underlying_type_t<ArgUsage>>;
139+
/// Expose the enum's underlying type because it simplifies bitwise operations.
140+
using ArgUsageUT = std::underlying_type_t<ArgUsage>;
137141

138142
///
139-
/// Describe the list of arguments by their kind.
143+
/// Describe the list of arguments by their kind and usage.
140144
struct SYCLArgumentDescriptor {
141-
std::vector<ParameterKind> Kinds;
145+
explicit SYCLArgumentDescriptor(size_t NumArgs)
146+
: Kinds(NumArgs), UsageMask(NumArgs){};
142147

143-
ArgUsageMask UsageMask;
148+
DynArray<ParameterKind> Kinds;
149+
DynArray<ArgUsageUT> UsageMask;
144150
};
145151

146152
///
@@ -312,8 +318,8 @@ struct SYCLKernelInfo {
312318
: Name{KernelName}, Args{ArgDesc}, Attributes{}, NDR{NDR}, BinaryInfo{
313319
BinInfo} {}
314320

315-
explicit SYCLKernelInfo(const std::string &KernelName)
316-
: Name{KernelName}, Args{}, Attributes{}, NDR{}, BinaryInfo{} {}
321+
SYCLKernelInfo(const std::string &KernelName, size_t NumArgs)
322+
: Name{KernelName}, Args{NumArgs}, Attributes{}, NDR{}, BinaryInfo{} {}
317323
};
318324

319325
///

sycl-fusion/passes/cleanup/Cleanup.cpp

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,8 @@ static Function *createMaskedFunction(const BitVector &Mask, Function *F,
8686
}
8787

8888
static void updateArgUsageMask(jit_compiler::SYCLKernelInfo *Info,
89-
const jit_compiler::ArgUsageMask &NewArgInfo) {
90-
// Masks iterator.
91-
jit_compiler::ArgUsageMask &KernelMask = Info->Args.UsageMask;
92-
89+
ArrayRef<jit_compiler::ArgUsageUT> NewArgInfo) {
90+
auto &KernelMask = Info->Args.UsageMask;
9391
auto New = NewArgInfo.begin();
9492
for (auto &C : KernelMask) {
9593
if (C & jit_compiler::ArgUsage::Used) {
@@ -105,7 +103,7 @@ static void updateArgUsageMask(jit_compiler::SYCLKernelInfo *Info,
105103
}
106104
}
107105

108-
static void applyArgMask(const jit_compiler::ArgUsageMask &NewArgInfo,
106+
static void applyArgMask(ArrayRef<jit_compiler::ArgUsageUT> NewArgInfo,
109107
const BitVector &Mask, Function *F,
110108
ModuleAnalysisManager &AM, TargetFusionInfo &TFI) {
111109
// Create the function without the masked-out args.
@@ -143,7 +141,7 @@ static void maskMD(const BitVector &Mask, Function *F) {
143141
}
144142
}
145143

146-
void llvm::fullCleanup(const jit_compiler::ArgUsageMask &ArgUsageInfo,
144+
void llvm::fullCleanup(ArrayRef<jit_compiler::ArgUsageUT> ArgUsageInfo,
147145
Function *F, ModuleAnalysisManager &AM,
148146
TargetFusionInfo &TFI, ArrayRef<StringRef> MDToErase) {
149147
// Erase metadata.

sycl-fusion/passes/cleanup/Cleanup.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ namespace llvm {
2525
/// @param[in] F Function to be cleaned.
2626
/// @param[in] AM Module analysis manager.
2727
/// @param[in] EraseMD Keys of metadata to remove.
28-
void fullCleanup(const jit_compiler::ArgUsageMask &ArgUsageInfo, Function *F,
28+
void fullCleanup(ArrayRef<::jit_compiler::ArgUsageUT> ArgUsageInfo, Function *F,
2929
ModuleAnalysisManager &AM, TargetFusionInfo &TFI,
3030
ArrayRef<StringRef> EraseMD);
3131
} // namespace llvm

sycl-fusion/passes/internalization/Internalization.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -664,7 +664,7 @@ static void moduleCleanup(Module &M, ModuleAnalysisManager &AM,
664664
// Use the argument usage mask to provide feedback to the runtime which
665665
// arguments have been promoted to private or local memory and which have
666666
// been eliminated in the process (private promotion).
667-
jit_compiler::ArgUsageMask NewArgInfo;
667+
SmallVector<jit_compiler::ArgUsageUT> NewArgInfo;
668668
for (auto I : enumerate(MD->operands())) {
669669
const auto &MDS = cast<MDString>(I.value().get())->getString();
670670
if (MDS == PrivatePromotion) {

sycl-fusion/passes/kernel-fusion/SYCLKernelFusion.cpp

Lines changed: 39 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -355,16 +355,12 @@ Error SYCLKernelFusion::fuseKernel(
355355
// Collect it, so it can be attached to the fused function later on.
356356
MetadataCollection MDCollection{TargetInfo.getKernelMetadataKeys()};
357357

358-
// Add the information about the new kernel to the SYCLModuleInfo.
359-
// Initialize the jit_compiler::SYCLKernelInfo with the name. The remaining
360-
// information for functor & argument layout and attributes will be filled in
361-
// with information from the input kernels below.
362-
if (!ModInfo->hasKernelFor(FusedKernelName.str())) {
363-
jit_compiler::SYCLKernelInfo KI{FusedKernelName.str()};
364-
ModInfo->addKernel(KI);
365-
}
366-
jit_compiler::SYCLKernelInfo &FusedKernelInfo =
367-
*ModInfo->getKernelFor(FusedKernelName.str());
358+
// Collect information for functor & argument layout and attributes from the
359+
// input kernels below.
360+
MutableParamKindList FusedParamKinds;
361+
MutableArgUsageMask FusedArgUsageMask;
362+
MutableAttributeList FusedAttributes;
363+
368364
// Mapping from parameter in an input function (index in the list of input
369365
// functions and index in the original function) to the argument index in the
370366
// fused function.
@@ -438,10 +434,25 @@ Error SYCLKernelFusion::fuseKernel(
438434
"No jit_compiler::SYCLKernelInfo found");
439435
jit_compiler::SYCLKernelInfo &InputKernelInfo =
440436
*ModInfo->getKernelFor(FN.str());
441-
appendKernelInfo(FusedKernelInfo, InputKernelInfo, UsedArgsMask);
437+
appendKernelInfo(FusedParamKinds, FusedArgUsageMask, FusedAttributes,
438+
InputKernelInfo, UsedArgsMask);
442439
++FuncIndex;
443440
}
444441

442+
// Add the information about the new kernel to the SYCLModuleInfo.
443+
if (!ModInfo->hasKernelFor(FusedKernelName.str())) {
444+
assert(FusedParamKinds.size() == FusedArgUsageMask.size());
445+
jit_compiler::SYCLKernelInfo KI{FusedKernelName.str(),
446+
FusedParamKinds.size()};
447+
llvm::copy(FusedParamKinds, KI.Args.Kinds.begin());
448+
llvm::copy(FusedArgUsageMask, KI.Args.UsageMask.begin());
449+
KI.Attributes.insert(KI.Attributes.end(), FusedAttributes.begin(),
450+
FusedAttributes.end());
451+
ModInfo->addKernel(KI);
452+
}
453+
jit_compiler::SYCLKernelInfo &FusedKernelInfo =
454+
*ModInfo->getKernelFor(FusedKernelName.str());
455+
445456
// Check that no function with the desired name is already present in the
446457
// module. LLVM would still be able to insert the function (adding a suffix to
447458
// the name), but we won't be able to correctly call it by its name at
@@ -706,7 +717,7 @@ void SYCLKernelFusion::attachKernelAttributeMD(
706717
}
707718

708719
void SYCLKernelFusion::updateArgUsageMask(
709-
jit_compiler::ArgUsageMask &NewMask,
720+
MutableArgUsageMask &NewMask,
710721
jit_compiler::SYCLArgumentDescriptor &InputDef,
711722
const ArrayRef<bool> ParamUseMask) const {
712723
// Create a new argument usage mask from the input information and the mask
@@ -730,32 +741,32 @@ void SYCLKernelFusion::updateArgUsageMask(
730741
}
731742

732743
void SYCLKernelFusion::appendKernelInfo(
733-
jit_compiler::SYCLKernelInfo &FusedInfo,
744+
MutableParamKindList &FusedParamKinds,
745+
MutableArgUsageMask &FusedArgUsageMask,
746+
MutableAttributeList &FusedAttributes,
734747
jit_compiler::SYCLKernelInfo &InputInfo,
735748
const ArrayRef<bool> ParamUseMask) const {
736749
// Add information from the input kernel to the SYCLKernelInfo of the fused
737750
// kernel.
738751

739752
// Add information about the input kernel's arguments to the KernelInfo for
740753
// the fused function.
741-
FusedInfo.Args.Kinds.insert(FusedInfo.Args.Kinds.end(),
742-
InputInfo.Args.Kinds.begin(),
743-
InputInfo.Args.Kinds.end());
754+
FusedParamKinds.append(InputInfo.Args.Kinds.begin(),
755+
InputInfo.Args.Kinds.end());
744756

745757
// Create a argument usage mask from input information and the mask resulting
746758
// from potential identical parameters.
747-
jit_compiler::ArgUsageMask NewMask;
759+
MutableArgUsageMask NewMask;
748760
updateArgUsageMask(NewMask, InputInfo.Args, ParamUseMask);
749-
FusedInfo.Args.UsageMask.insert(FusedInfo.Args.UsageMask.end(),
750-
NewMask.begin(), NewMask.end());
761+
FusedArgUsageMask.append(NewMask.begin(), NewMask.end());
751762

752763
// Merge the existing kernel attributes for the fused kernel (potentially
753764
// still empty) with the kernel attributes of the input kernel.
754-
mergeKernelAttributes(FusedInfo.Attributes, InputInfo.Attributes);
765+
mergeKernelAttributes(FusedAttributes, InputInfo.Attributes);
755766
}
756767

757768
void SYCLKernelFusion::mergeKernelAttributes(
758-
KernelAttributeList &Attributes, const KernelAttributeList &Other) const {
769+
MutableAttributeList &Attributes, const KernelAttributeList &Other) const {
759770
// For the current set of valid kernel attributes, it is sufficient to only
760771
// iterate over the list of new attributes coming in. In cases where the
761772
// existing list contains an attribute that is not present in the new list, we
@@ -834,30 +845,30 @@ SYCLKernelFusion::mergeWorkgroupSizeHint(KernelAttr *Attr,
834845
}
835846

836847
SYCLKernelFusion::KernelAttr *
837-
SYCLKernelFusion::getAttribute(KernelAttributeList &Attributes,
848+
SYCLKernelFusion::getAttribute(MutableAttributeList &Attributes,
838849
StringRef AttrName) const {
839-
SYCLKernelFusion::KernelAttrIterator It = findAttribute(Attributes, AttrName);
850+
auto *It = findAttribute(Attributes, AttrName);
840851
if (It != Attributes.end()) {
841852
return &*It;
842853
}
843854
return nullptr;
844855
}
845856

846-
void SYCLKernelFusion::addAttribute(KernelAttributeList &Attributes,
857+
void SYCLKernelFusion::addAttribute(MutableAttributeList &Attributes,
847858
const KernelAttr &Attr) const {
848859
Attributes.push_back(Attr);
849860
}
850861

851-
void SYCLKernelFusion::removeAttribute(KernelAttributeList &Attributes,
862+
void SYCLKernelFusion::removeAttribute(MutableAttributeList &Attributes,
852863
StringRef AttrName) const {
853-
SYCLKernelFusion::KernelAttrIterator It = findAttribute(Attributes, AttrName);
864+
auto *It = findAttribute(Attributes, AttrName);
854865
if (It != Attributes.end()) {
855866
Attributes.erase(It);
856867
}
857868
}
858869

859-
SYCLKernelFusion::KernelAttrIterator
860-
SYCLKernelFusion::findAttribute(KernelAttributeList &Attributes,
870+
SYCLKernelFusion::MutableAttributeList::iterator
871+
SYCLKernelFusion::findAttribute(MutableAttributeList &Attributes,
861872
StringRef AttrName) const {
862873
return llvm::find_if(Attributes, [=](SYCLKernelFusion::KernelAttr &Attr) {
863874
return Attr.AttributeName == AttrName.str();

sycl-fusion/passes/kernel-fusion/SYCLKernelFusion.h

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -129,20 +129,25 @@ class SYCLKernelFusion : public llvm::PassInfoMixin<SYCLKernelFusion> {
129129
llvm::Function *FusedFunction,
130130
jit_compiler::SYCLKernelInfo &FusedKernelInfo) const;
131131

132-
void appendKernelInfo(jit_compiler::SYCLKernelInfo &FusedInfo,
132+
using MutableParamKindList = llvm::SmallVector<jit_compiler::ParameterKind>;
133+
using MutableArgUsageMask = llvm::SmallVector<jit_compiler::ArgUsageUT>;
134+
using MutableAttributeList =
135+
llvm::SmallVector<jit_compiler::SYCLKernelAttribute>;
136+
137+
void appendKernelInfo(MutableParamKindList &FusedParamKinds,
138+
MutableArgUsageMask &FusedArgUsageMask,
139+
MutableAttributeList &FusedAttributes,
133140
jit_compiler::SYCLKernelInfo &InputInfo,
134141
const llvm::ArrayRef<bool> ParamUseMask) const;
135142

136-
void updateArgUsageMask(jit_compiler::ArgUsageMask &NewMask,
143+
void updateArgUsageMask(MutableArgUsageMask &NewMask,
137144
jit_compiler::SYCLArgumentDescriptor &InputDef,
138145
const llvm::ArrayRef<bool> ParamUseMask) const;
139146

140147
using KernelAttributeList = jit_compiler::AttributeList;
141148

142149
using KernelAttr = jit_compiler::SYCLKernelAttribute;
143150

144-
using KernelAttrIterator = KernelAttributeList::iterator;
145-
146151
///
147152
/// Indicates the result of merging two attributes of the same kind.
148153
enum class AttrMergeResult {
@@ -161,7 +166,7 @@ class SYCLKernelFusion : public llvm::PassInfoMixin<SYCLKernelFusion> {
161166
///
162167
/// Merge the content of Other into Attributes, adding, removing or updating
163168
/// attributes as needed.
164-
void mergeKernelAttributes(KernelAttributeList &Attributes,
169+
void mergeKernelAttributes(MutableAttributeList &Attributes,
165170
const KernelAttributeList &Other) const;
166171

167172
///
@@ -184,24 +189,24 @@ class SYCLKernelFusion : public llvm::PassInfoMixin<SYCLKernelFusion> {
184189
///
185190
/// Get the attribute with the specified name from the list or return nullptr
186191
/// in case no such attribute is present.
187-
KernelAttr *getAttribute(KernelAttributeList &Attributes,
192+
KernelAttr *getAttribute(MutableAttributeList &Attributes,
188193
llvm::StringRef AttrName) const;
189194

190195
///
191196
/// Add the attribute to the list.
192-
void addAttribute(KernelAttributeList &Attributes,
197+
void addAttribute(MutableAttributeList &Attributes,
193198
const KernelAttr &Attr) const;
194199

195200
///
196201
/// Remove the attribute with the specified name from the list, if present.
197-
void removeAttribute(KernelAttributeList &Attributes,
202+
void removeAttribute(MutableAttributeList &Attributes,
198203
llvm::StringRef AttrName) const;
199204

200205
///
201206
/// Find the attribute with the specified name in the list, or return the
202207
/// end() iterator if no such attribute is present.
203-
KernelAttrIterator findAttribute(KernelAttributeList &Attributes,
204-
llvm::StringRef AttrName) const;
208+
MutableAttributeList::iterator findAttribute(MutableAttributeList &Attributes,
209+
llvm::StringRef AttrName) const;
205210

206211
///
207212
/// Retrieve the attribute value at the given index as unsigned integer.

0 commit comments

Comments
 (0)