Skip to content

Commit 93a629a

Browse files
[SYCL] Implement two-run aspect propagation (#8681)
This commit splits aspect propagation into two runs: 1. First run propagates all aspects, except fp64. Warnings are still issued for fp64 as if it was fully propagated, but the resulting metadata will not reflect it. This run before optimizations. 2. Second run propagates all aspects, including fp64. This should not have any effect on already propagated aspects. This run will not issue warnings as any conflicts would have been reported by the first pass. See the [design document](https://github.com/intel/llvm/blob/sycl/sycl/doc/design/OptionalDeviceFeatures.md#pre--and-post-optimization-aspect-propagation) for more information. --------- Signed-off-by: Larsen, Steffen <[email protected]>
1 parent d31623a commit 93a629a

File tree

5 files changed

+254
-9
lines changed

5 files changed

+254
-9
lines changed

clang/lib/CodeGen/BackendUtil.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -911,7 +911,8 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
911911
PB.registerPipelineStartEPCallback(
912912
[&](ModulePassManager &MPM, OptimizationLevel Level) {
913913
MPM.addPass(ESIMDVerifierPass(LangOpts.SYCLESIMDForceStatelessMem));
914-
MPM.addPass(SYCLPropagateAspectsUsagePass());
914+
MPM.addPass(
915+
SYCLPropagateAspectsUsagePass(/*ExcludeAspects=*/{"fp64"}));
915916
});
916917

917918
// Add the InferAddressSpaces pass for all the SPIR[V] targets
@@ -1026,6 +1027,10 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
10261027
if (LangOpts.EnableDAEInSpirKernels)
10271028
MPM.addPass(DeadArgumentEliminationSYCLPass());
10281029

1030+
// Rerun aspect propagation without warning diagnostics.
1031+
MPM.addPass(SYCLPropagateAspectsUsagePass(/*ExcludeAspects=*/{},
1032+
/*ValidateAspects=*/false));
1033+
10291034
// Add SPIRITTAnnotations pass to the pass manager if
10301035
// -fsycl-instrument-device-code option was passed. This option can be
10311036
// used only with spir triple.

llvm/include/llvm/SYCLLowerIR/SYCLPropagateAspectsUsage.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,19 @@ namespace llvm {
2020
class SYCLPropagateAspectsUsagePass
2121
: public PassInfoMixin<SYCLPropagateAspectsUsagePass> {
2222
public:
23-
SYCLPropagateAspectsUsagePass(StringRef OptionsString = {}) {
23+
SYCLPropagateAspectsUsagePass(std::set<StringRef> ExcludeAspects = {},
24+
bool ValidateAspects = true,
25+
StringRef OptionsString = {})
26+
: ExcludedAspects{std::move(ExcludeAspects)},
27+
ValidateAspectUsage{ValidateAspects} {
2428
OptionsString.split(this->TargetFixedAspects, ',', /*MaxSplit=*/-1,
2529
/*KeepEmpty=*/false);
2630
};
2731
PreservedAnalyses run(Module &M, ModuleAnalysisManager &);
2832

2933
private:
34+
std::set<StringRef> ExcludedAspects;
35+
const bool ValidateAspectUsage;
3036
SmallVector<StringRef, 8> TargetFixedAspects;
3137
};
3238

llvm/lib/SYCLLowerIR/SYCLPropagateAspectsUsage.cpp

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@ static cl::opt<std::string> ClSyclFixedTargets(
5353
"is expected to be runnable on"),
5454
cl::Hidden, cl::init(""));
5555

56+
static cl::opt<std::string> ClSyclExcludeAspects(
57+
"sycl-propagate-aspects-usage-exclude-aspects",
58+
cl::desc("Specify aspects to exclude when propagating aspect usage"),
59+
cl::Hidden, cl::init(""));
60+
5661
namespace {
5762

5863
using AspectsSetTy = SmallSet<int, 4>;
@@ -293,15 +298,37 @@ getAspectUsageChain(const Function *F, const FunctionToAspectsMapTy &AspectsMap,
293298
return CallChain;
294299
}
295300

296-
void createUsedAspectsMetadataForFunctions(FunctionToAspectsMapTy &Map) {
301+
void createUsedAspectsMetadataForFunctions(
302+
FunctionToAspectsMapTy &Map, const AspectsSetTy &ExcludeAspectVals) {
297303
for (auto &[F, Aspects] : Map) {
298304
if (Aspects.empty())
299305
continue;
300306

301307
LLVMContext &C = F->getContext();
302308

309+
// Create a set of unique aspects. First we add the ones from the found
310+
// aspects that have not been excluded.
311+
AspectsSetTy UniqueAspects;
312+
for (const int &A : Aspects)
313+
if (!ExcludeAspectVals.contains(A))
314+
UniqueAspects.insert(A);
315+
316+
// If there are no new aspects, we can just keep the old metadata.
317+
if (UniqueAspects.empty())
318+
continue;
319+
320+
// If there is new metadata, merge it with the old aspects. We preserve
321+
// the excluded ones.
322+
if (const MDNode *ExistingAspects = F->getMetadata("sycl_used_aspects")) {
323+
for (const MDOperand &MDOp : ExistingAspects->operands()) {
324+
const Constant *C = cast<ConstantAsMetadata>(MDOp)->getValue();
325+
UniqueAspects.insert(cast<ConstantInt>(C)->getSExtValue());
326+
}
327+
}
328+
329+
// Create new metadata.
303330
SmallVector<Metadata *, 16> AspectsMetadata;
304-
for (const auto &A : Aspects)
331+
for (const int &A : UniqueAspects)
305332
AspectsMetadata.push_back(ConstantAsMetadata::get(
306333
ConstantInt::getSigned(Type::getInt32Ty(C), A)));
307334

@@ -506,7 +533,8 @@ void setSyclFixedTargetsMD(const std::vector<Function *> &EntryPoints,
506533
FunctionToAspectsMapTy
507534
buildFunctionsToAspectsMap(Module &M, TypeToAspectsMapTy &TypesWithAspects,
508535
const AspectValueToNameMapTy &AspectValues,
509-
const std::vector<Function *> &EntryPoints) {
536+
const std::vector<Function *> &EntryPoints,
537+
bool ValidateAspects) {
510538
FunctionToAspectsMapTy FunctionToUsedAspects;
511539
FunctionToAspectsMapTy FunctionToDeclaredAspects;
512540
CallGraphTy CG;
@@ -522,8 +550,9 @@ buildFunctionsToAspectsMap(Module &M, TypeToAspectsMapTy &TypesWithAspects,
522550
for (Function *F : EntryPoints)
523551
propagateAspectsThroughCG(F, CG, FunctionToUsedAspects, Visited);
524552

525-
validateUsedAspectsForFunctions(FunctionToUsedAspects, AspectValues,
526-
EntryPoints, CG);
553+
if (ValidateAspects)
554+
validateUsedAspectsForFunctions(FunctionToUsedAspects, AspectValues,
555+
EntryPoints, CG);
527556

528557
// The set of aspects from FunctionToDeclaredAspects should be merged to the
529558
// set of FunctionToUsedAspects after validateUsedAspectsForFunctions call to
@@ -558,6 +587,14 @@ SYCLPropagateAspectsUsagePass::run(Module &M, ModuleAnalysisManager &MAM) {
558587
StringRef(ClSyclFixedTargets)
559588
.split(TargetFixedAspects, ',', /*MaxSplit=*/-1, /*KeepEmpty=*/false);
560589

590+
if (ClSyclExcludeAspects.getNumOccurrences() > 0) {
591+
SmallVector<StringRef, 4> ExcludedAspectsVec;
592+
StringRef(ClSyclExcludeAspects)
593+
.split(ExcludedAspectsVec, ',', /*MaxSplit=*/-1, /*KeepEmpty=*/false);
594+
ExcludedAspects.insert(ExcludedAspectsVec.begin(),
595+
ExcludedAspectsVec.end());
596+
}
597+
561598
std::vector<Function *> EntryPoints;
562599
for (Function &F : M.functions())
563600
if (isEntryPoint(F))
@@ -566,9 +603,19 @@ SYCLPropagateAspectsUsagePass::run(Module &M, ModuleAnalysisManager &MAM) {
566603
propagateAspectsToOtherTypesInModule(M, TypesWithAspects, AspectValues);
567604

568605
FunctionToAspectsMapTy FunctionToUsedAspects = buildFunctionsToAspectsMap(
569-
M, TypesWithAspects, AspectValues, EntryPoints);
606+
M, TypesWithAspects, AspectValues, EntryPoints, ValidateAspectUsage);
607+
608+
// Create a set of excluded aspect values.
609+
AspectsSetTy ExcludedAspectVals;
610+
for (const StringRef &AspectName : ExcludedAspects) {
611+
const auto AspectValIter = AspectValues.find(AspectName);
612+
assert(AspectValIter != AspectValues.end() &&
613+
"Excluded aspect does not have a corresponding value.");
614+
ExcludedAspectVals.insert(AspectValIter->second);
615+
}
570616

571-
createUsedAspectsMetadataForFunctions(FunctionToUsedAspects);
617+
createUsedAspectsMetadataForFunctions(FunctionToUsedAspects,
618+
ExcludedAspectVals);
572619

573620
setSyclFixedTargetsMD(EntryPoints, TargetFixedAspects, AspectValues);
574621

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
; RUN: opt -passes=sycl-propagate-aspects-usage -sycl-propagate-aspects-usage-exclude-aspects=fp64 < %s -S -o %t_first.ll
2+
; RUN: opt -passes=sycl-propagate-aspects-usage < %t_first.ll -S -o %t_second.ll
3+
; FileCheck %s --input-file %t_first.ll --check-prefix=CHECK-FIRST
4+
; FileCheck %s --input-file %t_second.ll --check-prefix=CHECK-SECOND
5+
;
6+
; Test checks that fp64 usage is correctly propagate in the two-run model.
7+
8+
%composite = type { double }
9+
10+
; CHECK-FIRST-NOT: spir_kernel void @kernel() {{.*}} !sycl_used_aspects
11+
; CHECK-SECOND: spir_kernel void @kernel() !sycl_used_aspects ![[MDID:]]
12+
define spir_kernel void @kernel() {
13+
call spir_func void @func()
14+
ret void
15+
}
16+
17+
; CHECK-FIRST-NOT: spir_func void @func() {{.*}} !sycl_used_aspects
18+
; CHECK-SECOND: spir_func void @func() !sycl_used_aspects ![[MDID]] {
19+
define spir_func void @func() {
20+
%tmp = alloca double
21+
ret void
22+
}
23+
24+
; CHECK-FIRST-NOT: spir_func void @func.array() {{.*}} !sycl_used_aspects
25+
; CHECK-SECOND: spir_func void @func.array() !sycl_used_aspects ![[MDID]] {
26+
define spir_func void @func.array() {
27+
%tmp = alloca [4 x double]
28+
ret void
29+
}
30+
31+
; CHECK-FIRST-NOT: spir_func void @func.vector() {{.*}} !sycl_used_aspects
32+
; CHECK-SECOND: spir_func void @func.vector() !sycl_used_aspects ![[MDID]] {
33+
define spir_func void @func.vector() {
34+
%tmp = alloca <4 x double>
35+
ret void
36+
}
37+
38+
; CHECK-FIRST-NOT: spir_func void @func.composite() {{.*}} !sycl_used_aspects
39+
; CHECK-SECOND: spir_func void @func.composite() !sycl_used_aspects ![[MDID]] {
40+
define spir_func void @func.composite() {
41+
%tmp = alloca %composite
42+
ret void
43+
}
44+
45+
!sycl_aspects = !{!0}
46+
!0 = !{!"fp64", i32 6}
47+
48+
; CHECK-SECOND: ![[MDID]] = !{i32 6}
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
; RUN: opt -passes=sycl-propagate-aspects-usage -sycl-propagate-aspects-usage-exclude-aspects=aspect4,aspect1 -S < %s | FileCheck %s
2+
;
3+
; Test checks that the pass is able to collect all aspects used in a function
4+
5+
%A = type { i32 }
6+
%B = type { i32 }
7+
%C = type { i32 }
8+
%D = type { i32 }
9+
10+
; None of funcA's aspects are excluded.
11+
; CHECK: define spir_func void @funcA() !sycl_used_aspects ![[#ID0:]] {
12+
define spir_func void @funcA() {
13+
%tmp = alloca %A
14+
ret void
15+
}
16+
17+
; funcB uses "aspect1" which is excluded, so the resulting aspects are the same
18+
; as for funcA.
19+
; CHECK: define spir_func void @funcB() !sycl_used_aspects ![[#ID0]] {
20+
define spir_func void @funcB() {
21+
%tmp = alloca %B
22+
call spir_func void @funcA()
23+
ret void
24+
}
25+
26+
; funcC has an aspect excluded, propagated from funcB.
27+
; CHECK: define spir_func void @funcC() !sycl_used_aspects ![[#ID1:]] {
28+
define spir_func void @funcC() {
29+
%tmp = alloca %C
30+
call spir_func void @funcB()
31+
ret void
32+
}
33+
34+
; funcD has two aspects excluded; one from the use of D and one from propagated.
35+
; from funcB and funcC.
36+
; CHECK: define spir_func void @funcD() !sycl_used_aspects ![[#ID2:]] {
37+
define spir_func void @funcD() {
38+
%tmp = alloca %D
39+
call spir_func void @funcC()
40+
ret void
41+
}
42+
43+
; kernel1 has the same aspects as funcD.
44+
; CHECK: define spir_kernel void @kernel1() !sycl_used_aspects ![[#ID2]]
45+
define spir_kernel void @kernel1() {
46+
call spir_func void @funcD()
47+
ret void
48+
}
49+
50+
; funcE should get none of its explicitly declared aspects in its
51+
; sycl_used_aspects
52+
; CHECK: define spir_func void @funcE() !sycl_declared_aspects ![[#DA1:]] {
53+
define spir_func void @funcE() !sycl_declared_aspects !10 {
54+
ret void
55+
}
56+
57+
; funcF should have the same aspects as funcE
58+
; CHECK-NOT: define spir_func void @funcF() {{.*}} !sycl_used_aspects
59+
define spir_func void @funcF() {
60+
call spir_func void @funcE()
61+
ret void
62+
}
63+
64+
; funcG only keeps one aspect, the rest are excluded
65+
; CHECK: define spir_func void @funcG() !sycl_declared_aspects ![[#DA2:]] !sycl_used_aspects ![[#ID3:]]
66+
define spir_func void @funcG() !sycl_declared_aspects !11 {
67+
ret void
68+
}
69+
70+
; funcH should have the same aspects as funcG
71+
; CHECK: define spir_func void @funcH() !sycl_used_aspects ![[#ID3]]
72+
define spir_func void @funcH() {
73+
call spir_func void @funcG()
74+
ret void
75+
}
76+
77+
; CHECK: define spir_kernel void @kernel2() !sycl_used_aspects ![[#ID3]]
78+
define spir_kernel void @kernel2() {
79+
call spir_func void @funcF()
80+
call spir_func void @funcH()
81+
ret void
82+
}
83+
84+
; CHECK: define spir_func void @funcI() !sycl_used_aspects ![[#DA1]] {
85+
define spir_func void @funcI() !sycl_used_aspects !10 {
86+
ret void
87+
}
88+
89+
; CHECK-NOT: define spir_func void @funcJ() {{.*}} !sycl_used_aspects
90+
define spir_func void @funcJ() {
91+
call spir_func void @funcI()
92+
ret void
93+
}
94+
95+
;
96+
; Note that the listed aspects can be reordered due to the merging of the
97+
; aspect sets.
98+
; CHECK: define spir_func void @funcK() !sycl_used_aspects ![[#ID4:]] {
99+
define spir_func void @funcK() !sycl_used_aspects !11 {
100+
ret void
101+
}
102+
103+
; CHECK: define spir_func void @funcL() !sycl_used_aspects ![[#ID3]]
104+
define spir_func void @funcL() {
105+
call spir_func void @funcK()
106+
ret void
107+
}
108+
109+
; CHECK: define spir_kernel void @kernel3() !sycl_used_aspects ![[#ID3]]
110+
define spir_kernel void @kernel3() {
111+
call spir_func void @funcK()
112+
call spir_func void @funcL()
113+
ret void
114+
}
115+
116+
!sycl_types_that_use_aspects = !{!0, !1, !2, !3}
117+
!0 = !{!"A", i32 0}
118+
!1 = !{!"B", i32 1}
119+
!2 = !{!"C", i32 2}
120+
!3 = !{!"D", i32 3, i32 4}
121+
122+
!sycl_aspects = !{!4, !5, !6, !7, !8, !9}
123+
!4 = !{!"aspect0", i32 0}
124+
!5 = !{!"aspect1", i32 1}
125+
!6 = !{!"aspect2", i32 2}
126+
!7 = !{!"aspect3", i32 3}
127+
!8 = !{!"aspect4", i32 4}
128+
!9 = !{!"fp64", i32 5}
129+
130+
!10 = !{i32 1}
131+
!11 = !{i32 4, i32 2, i32 1}
132+
; CHECK-DAG: ![[#DA1]] = !{i32 1}
133+
; CHECK-DAG: ![[#DA2]] = !{i32 4, i32 2, i32 1}
134+
135+
; CHECK-DAG: ![[#ID0]] = !{i32 0}
136+
; CHECK-DAG: ![[#ID1]] = !{i32 2, i32 0}
137+
; CHECK-DAG: ![[#ID2]] = !{i32 0, i32 2, i32 3}
138+
; CHECK-DAG: ![[#ID3]] = !{i32 2}
139+
; CHECK-DAG: ![[#ID4]] = !{i32 2, i32 4, i32 1}

0 commit comments

Comments
 (0)