Skip to content

Commit 332e4ee

Browse files
[SYCL] Add kernel property parsing to sycl-post-link (#7017)
This commit adds parsing of compile-time properties for kernels to sycl-post-link. This includes the following: * sycl-post-link is now able to generate metadata for recognized SYCL LLVM IR attributes on functions. These are "sycl-work-group-size", "sycl-work-group-size-hint", and "sycl-sub-group-size". * The previously mentioned new recognized LLVM IR attributes are translated into existing metadata the SPIR-V Translator translates into corresponding SPIR-V execution modes. If these metadata nodes already exist on a function (e.g. added through a SYCL 2020 attribute), the related property is ignored. This is split from #6941. Signed-off-by: Larsen, Steffen <[email protected]>
1 parent 404b8e3 commit 332e4ee

File tree

2 files changed

+188
-12
lines changed

2 files changed

+188
-12
lines changed
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
; RUN: sycl-post-link --ir-output-only --device-globals %s -S -o - | FileCheck %s --check-prefix CHECK-IR
2+
3+
; CHECK-IR-DAG: @"_ZTSZZ4mainENK3$_0clERN2cl4sycl7handlerEE9TheKernel0"() #0 {{.*}}!intel_reqd_sub_group_size ![[SGSizeMD0:[0-9]+]] {{.*}}!reqd_work_group_size ![[WGSizeMD0:[0-9]+]]{{.*}}!work_group_size_hint ![[WGSizeHintMD0:[0-9]+]]
4+
; Function Attrs: convergent norecurse
5+
define weak_odr dso_local spir_kernel void @"_ZTSZZ4mainENK3$_0clERN2cl4sycl7handlerEE9TheKernel0"() #0 {
6+
entry:
7+
ret void
8+
}
9+
10+
; CHECK-IR-DAG: @"_ZTSZZ4mainENK3$_0clERN2cl4sycl7handlerEE9TheKernel1"() #1 {{.*}}!reqd_work_group_size ![[WGSizeMD1:[0-9]+]]{{.*}}!work_group_size_hint ![[WGSizeHintMD1:[0-9]+]]
11+
; Function Attrs: convergent norecurse
12+
define weak_odr dso_local spir_kernel void @"_ZTSZZ4mainENK3$_0clERN2cl4sycl7handlerEE9TheKernel1"() #1 {
13+
entry:
14+
ret void
15+
}
16+
17+
; CHECK-IR-DAG: @"_ZTSZZ4mainENK3$_0clERN2cl4sycl7handlerEE9TheKernel2"() #2 {{.*}}!reqd_work_group_size ![[WGSizeMD2:[0-9]+]]{{.*}}!work_group_size_hint ![[WGSizeHintMD2:[0-9]+]]
18+
; Function Attrs: convergent norecurse
19+
define weak_odr dso_local spir_kernel void @"_ZTSZZ4mainENK3$_0clERN2cl4sycl7handlerEE9TheKernel2"() #2 {
20+
entry:
21+
ret void
22+
}
23+
24+
attributes #0 = { convergent norecurse "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "sycl-module-id"="kernel_properties.cpp" "uniform-work-group-size"="true" "sycl-work-group-size"="1" "sycl-work-group-size-hint"="2" "sycl-sub-group-size"="3" }
25+
attributes #1 = { convergent norecurse "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "sycl-module-id"="kernel_properties.cpp" "uniform-work-group-size"="true" "sycl-work-group-size"="4,5" "sycl-work-group-size-hint"="6,7" }
26+
attributes #2 = { convergent norecurse "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "sycl-module-id"="kernel_properties.cpp" "uniform-work-group-size"="true" "sycl-work-group-size"="8,9,10" "sycl-work-group-size-hint"="11,12,13" }
27+
28+
!opencl.spir.version = !{!0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0}
29+
!spirv.Source = !{!1, !1, !1, !1, !1, !1, !1, !1, !1, !1, !1}
30+
!llvm.ident = !{!2, !2, !2, !2, !2, !2, !2, !2, !2, !2, !2}
31+
!llvm.module.flags = !{!3, !4}
32+
33+
!0 = !{i32 1, i32 2}
34+
!1 = !{i32 4, i32 100000}
35+
!2 = !{!"clang version 13.0.0 (https://github.com/intel/llvm)"}
36+
!3 = !{i32 1, !"wchar_size", i32 4}
37+
!4 = !{i32 7, !"frame-pointer", i32 2}
38+
39+
; Note that work-group sizes are padded with 1's after being reversed.
40+
; CHECK-IR-DAG: ![[SGSizeMD0]] = !{i32 3}
41+
; CHECK-IR-DAG: ![[WGSizeMD0]] = !{i{{[0-9]+}} 1, i{{[0-9]+}} 1, i{{[0-9]+}} 1}
42+
; CHECK-IR-DAG: ![[WGSizeHintMD0]] = !{i{{[0-9]+}} 2, i{{[0-9]+}} 1, i{{[0-9]+}} 1}
43+
; CHECK-IR-DAG: ![[WGSizeMD1]] = !{i{{[0-9]+}} 5, i{{[0-9]+}} 4, i{{[0-9]+}} 1}
44+
; CHECK-IR-DAG: ![[WGSizeHintMD1]] = !{i{{[0-9]+}} 7, i{{[0-9]+}} 6, i{{[0-9]+}} 1}
45+
; CHECK-IR-DAG: ![[WGSizeMD2]] = !{i{{[0-9]+}} 10, i{{[0-9]+}} 9, i{{[0-9]+}} 8}
46+
; CHECK-IR-DAG: ![[WGSizeHintMD2]] = !{i{{[0-9]+}} 13, i{{[0-9]+}} 12, i{{[0-9]+}} 11}

llvm/tools/sycl-post-link/CompileTimePropertiesPass.cpp

Lines changed: 142 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,15 @@ MDNode *buildSpirvDecorMetadata(LLVMContext &Ctx, uint32_t OpCode,
9393
return MDNode::get(Ctx, MD);
9494
}
9595

96+
/// Gets the string value in a global variable. If the parameter is not a global
97+
/// variable or it does not contain string data, then \c None is returned.
98+
///
99+
/// @param StringV [in] the LLVM value of supposed \c GlobalVariable type with
100+
/// a string value.
101+
///
102+
/// @returns a \c StringRef with the string contained in \c StringV and \c None
103+
/// if \c StringV is not a \c GlobalVariable or does not contain string
104+
/// data.
96105
Optional<StringRef> getGlobalVariableString(const Value *StringV) {
97106
if (const auto *StringGV = dyn_cast<GlobalVariable>(StringV))
98107
if (const auto *StringData =
@@ -102,6 +111,106 @@ Optional<StringRef> getGlobalVariableString(const Value *StringV) {
102111
return {};
103112
}
104113

114+
/// Tries to generate a SPIR-V decorate metadata node from an attribute. If
115+
/// the attribute is unknown \c nullptr will be returned.
116+
///
117+
/// @param Ctx [in] the LLVM context.
118+
/// @param Attr [in] the LLVM attribute to generate metadata for.
119+
///
120+
/// @returns a pointer to a new metadata node if \c Attr is an attribute with a
121+
/// known corresponding SPIR-V decorate and the arguments are valid.
122+
/// Otherwise \c nullptr is returned.
123+
MDNode *attributeToDecorateMetadata(LLVMContext &Ctx, const Attribute &Attr) {
124+
// Currently, only string attributes are supported
125+
if (!Attr.isStringAttribute())
126+
return nullptr;
127+
auto DecorIt = SpirvDecorMap.find(Attr.getKindAsString());
128+
if (DecorIt == SpirvDecorMap.end())
129+
return nullptr;
130+
Decor DecorFound = DecorIt->second;
131+
uint32_t DecorCode = DecorFound.Code;
132+
switch (DecorFound.Type) {
133+
case DecorValueTy::uint32:
134+
return buildSpirvDecorMetadata(Ctx, DecorCode,
135+
getAttributeAsInteger<uint32_t>(Attr));
136+
case DecorValueTy::boolean:
137+
return buildSpirvDecorMetadata(Ctx, DecorCode, hasProperty(Attr));
138+
default:
139+
llvm_unreachable("Unhandled decorator type.");
140+
}
141+
}
142+
143+
/// Tries to generate a SPIR-V execution mode metadata node from an attribute.
144+
/// If the attribute is unknown \c None will be returned.
145+
///
146+
/// @param M [in] the LLVM module.
147+
/// @param Attr [in] the LLVM attribute to generate metadata for.
148+
///
149+
/// @returns a pair with the name of the resulting metadata and a pointer to
150+
/// the metadata node with its values if the attribute has a
151+
/// corresponding SPIR-V execution mode. Otherwise \c None is returned.
152+
Optional<std::pair<std::string, MDNode *>>
153+
attributeToExecModeMetadata(Module &M, const Attribute &Attr) {
154+
LLVMContext &Ctx = M.getContext();
155+
const DataLayout &DLayout = M.getDataLayout();
156+
157+
// Currently, only string attributes are supported
158+
if (!Attr.isStringAttribute())
159+
return None;
160+
StringRef AttrKindStr = Attr.getKindAsString();
161+
// Early exit if it is not a sycl-* attribute.
162+
if (!AttrKindStr.startswith("sycl-"))
163+
return None;
164+
165+
if (AttrKindStr == "sycl-work-group-size" ||
166+
AttrKindStr == "sycl-work-group-size-hint") {
167+
// Split values in the comma-separated list integers.
168+
SmallVector<StringRef, 3> ValStrs;
169+
Attr.getValueAsString().split(ValStrs, ',');
170+
171+
assert(ValStrs.size() <= 3 &&
172+
"sycl-work-group-size and sycl-work-group-size-hint currently only "
173+
"support up to three values");
174+
175+
// SYCL work-group sizes must be reversed for SPIR-V.
176+
std::reverse(ValStrs.begin(), ValStrs.end());
177+
178+
// Use integer pointer size as closest analogue to size_t.
179+
IntegerType *IntPtrTy = DLayout.getIntPtrType(Ctx);
180+
IntegerType *SizeTTy = Type::getIntNTy(Ctx, IntPtrTy->getBitWidth());
181+
unsigned SizeTBitSize = SizeTTy->getBitWidth();
182+
183+
// Get the integers from the strings.
184+
SmallVector<Metadata *, 3> MDVals;
185+
for (StringRef ValStr : ValStrs)
186+
MDVals.push_back(ConstantAsMetadata::get(Constant::getIntegerValue(
187+
SizeTTy, APInt(SizeTBitSize, ValStr, 10))));
188+
189+
// The SPIR-V translator expects 3 values, so we pad the remaining
190+
// dimensions with 1.
191+
for (size_t I = MDVals.size(); I < 3; ++I)
192+
MDVals.push_back(ConstantAsMetadata::get(
193+
Constant::getIntegerValue(SizeTTy, APInt(SizeTBitSize, 1))));
194+
195+
const char *MDName = (AttrKindStr == "sycl-work-group-size")
196+
? "reqd_work_group_size"
197+
: "work_group_size_hint";
198+
return std::pair<std::string, MDNode *>(MDName, MDNode::get(Ctx, MDVals));
199+
}
200+
201+
if (AttrKindStr == "sycl-sub-group-size") {
202+
uint32_t SubGroupSize = getAttributeAsInteger<uint32_t>(Attr);
203+
IntegerType *Ty = Type::getInt32Ty(Ctx);
204+
Metadata *MDVal = ConstantAsMetadata::get(
205+
Constant::getIntegerValue(Ty, APInt(32, SubGroupSize)));
206+
SmallVector<Metadata *, 1> MD{MDVal};
207+
return std::pair<std::string, MDNode *>("intel_reqd_sub_group_size",
208+
MDNode::get(Ctx, MD));
209+
}
210+
211+
return None;
212+
}
213+
105214
} // anonymous namespace
106215

107216
PreservedAnalyses CompileTimePropertiesPass::run(Module &M,
@@ -117,18 +226,9 @@ PreservedAnalyses CompileTimePropertiesPass::run(Module &M,
117226
// decorations in the SPV_INTEL_* extensions.
118227
SmallVector<Metadata *, 8> MDOps;
119228
for (auto &Attribute : GV.getAttributes()) {
120-
// Currently, only string attributes are supported
121-
if (!Attribute.isStringAttribute())
122-
continue;
123-
auto DecorIt = SpirvDecorMap.find(Attribute.getKindAsString());
124-
if (DecorIt == SpirvDecorMap.end())
125-
continue;
126-
auto Decor = DecorIt->second;
127-
auto DecorCode = Decor.Code;
128-
auto DecorValue = Decor.Type == DecorValueTy::uint32
129-
? getAttributeAsInteger<uint32_t>(Attribute)
130-
: hasProperty(Attribute);
131-
MDOps.push_back(buildSpirvDecorMetadata(Ctx, DecorCode, DecorValue));
229+
MDNode *SPIRVMetadata = attributeToDecorateMetadata(Ctx, Attribute);
230+
if (SPIRVMetadata)
231+
MDOps.push_back(SPIRVMetadata);
132232
}
133233

134234
// Some properties should be handled specially.
@@ -154,6 +254,36 @@ PreservedAnalyses CompileTimePropertiesPass::run(Module &M,
154254
}
155255
}
156256

257+
// Process all properties on kernels.
258+
for (Function &F : M) {
259+
// Only consider kernels.
260+
if (F.getCallingConv() != CallingConv::SPIR_KERNEL)
261+
continue;
262+
263+
SmallVector<Metadata *, 8> MDOps;
264+
SmallVector<std::pair<std::string, MDNode *>, 8> NamedMDOps;
265+
for (const Attribute &Attribute : F.getAttributes().getFnAttrs()) {
266+
if (MDNode *SPIRVMetadata = attributeToDecorateMetadata(Ctx, Attribute))
267+
MDOps.push_back(SPIRVMetadata);
268+
else if (auto NamedMetadata = attributeToExecModeMetadata(M, Attribute))
269+
NamedMDOps.push_back(*NamedMetadata);
270+
}
271+
272+
// Add the generated metadata to the kernel function.
273+
if (!MDOps.empty()) {
274+
F.addMetadata(MDKindID, *MDNode::get(Ctx, MDOps));
275+
CompileTimePropertiesMet = true;
276+
}
277+
278+
// Add the new named metadata to the kernel function.
279+
for (std::pair<std::string, MDNode *> NamedMD : NamedMDOps) {
280+
// If multiple sources defined this metadata, prioritize the existing one.
281+
if (F.hasMetadata(NamedMD.first))
282+
continue;
283+
F.addMetadata(NamedMD.first, *NamedMD.second);
284+
}
285+
}
286+
157287
// Check pointer annotations.
158288
SmallVector<IntrinsicInst *, 4> RemovableAnnots;
159289
for (Function &F : M)

0 commit comments

Comments
 (0)