-
Notifications
You must be signed in to change notification settings - Fork 796
[SYCL] Update aspect propagation for virtual functions #15703
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
766ca16
db5e083
6a45f70
9455285
8735bf5
97a8424
52f7ab8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -647,6 +647,38 @@ void setSyclFixedTargetsMD(const std::vector<Function *> &EntryPoints, | |
| F->setMetadata("sycl_fixed_targets", MDN); | ||
| } | ||
|
|
||
| void collectVirtualFunctionSetInfo( | ||
| Function &F, StringMap<std::vector<Function *>> &VirtualFunctionSets) { | ||
| if (!F.hasFnAttribute("indirectly-callable")) | ||
| return; | ||
| Attribute IndirectlyCallableAttr = F.getFnAttribute("indirectly-callable"); | ||
| StringRef SetName = IndirectlyCallableAttr.getValueAsString(); | ||
| VirtualFunctionSets[SetName].push_back(&F); | ||
| } | ||
|
|
||
| // For each set S of virtual functions that F declares, | ||
| // propagate S through the CG and then add the aspects | ||
| // used by S to F. | ||
| void processDeclaredVirtualFunctionSets( | ||
| Function *F, CallGraphTy &CG, FunctionToAspectsMapTy &AspectsMap, | ||
| SmallPtrSet<const Function *, 16> &Visited, | ||
| StringMap<std::vector<Function *>> &VirtualFunctionSets) { | ||
| if (!F->hasFnAttribute("calls-indirectly")) | ||
| return; | ||
| Attribute CallsIndirectlyAttr = F->getFnAttribute("calls-indirectly"); | ||
| SmallVector<StringRef, 4> DeclaredVirtualFunctionSetNames; | ||
| CallsIndirectlyAttr.getValueAsString().split(DeclaredVirtualFunctionSetNames, | ||
| ","); | ||
| auto &AspectsF = AspectsMap[F]; | ||
| for (auto Name : DeclaredVirtualFunctionSetNames) { | ||
| for (auto VFn : VirtualFunctionSets[Name]) { | ||
| propagateAspectsThroughCG(VFn, CG, AspectsMap, Visited); | ||
| for (auto Aspect : AspectsMap[VFn]) | ||
| AspectsF.insert(Aspect); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /// Returns a map of functions with corresponding used aspects. | ||
| std::pair<FunctionToAspectsMapTy, FunctionToAspectsMapTy> | ||
| buildFunctionsToAspectsMap(Module &M, TypeToAspectsMapTy &TypesWithAspects, | ||
|
|
@@ -655,16 +687,21 @@ buildFunctionsToAspectsMap(Module &M, TypeToAspectsMapTy &TypesWithAspects, | |
| bool ValidateAspects, bool FP64ConvEmu) { | ||
| FunctionToAspectsMapTy FunctionToUsedAspects; | ||
| FunctionToAspectsMapTy FunctionToDeclaredAspects; | ||
| StringMap<std::vector<Function *>> VirtualFunctionSets; | ||
|
||
| CallGraphTy CG; | ||
|
|
||
| for (Function &F : M.functions()) { | ||
| processFunction(F, FunctionToUsedAspects, FunctionToDeclaredAspects, | ||
| TypesWithAspects, CG, AspectValues, FP64ConvEmu); | ||
| collectVirtualFunctionSetInfo(F, VirtualFunctionSets); | ||
| } | ||
|
|
||
| SmallPtrSet<const Function *, 16> Visited; | ||
| for (Function *F : EntryPoints) | ||
| for (Function *F : EntryPoints) { | ||
| propagateAspectsThroughCG(F, CG, FunctionToUsedAspects, Visited); | ||
| processDeclaredVirtualFunctionSets(F, CG, FunctionToUsedAspects, Visited, | ||
| VirtualFunctionSets); | ||
| } | ||
|
|
||
| if (ValidateAspects) | ||
| validateUsedAspectsForFunctions(FunctionToUsedAspects, AspectValues, | ||
|
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we put those into a subfolder to make codebase cleaner (in case we add more tests and in general)? |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| ; RUN: opt -passes=sycl-propagate-aspects-usage < %s -S | FileCheck %s | ||
|
|
||
| ; CHECK: @vfn() #0 !sycl_used_aspects ![[#aspects:]] | ||
| define spir_func void @vfn() #0 { | ||
| %tmp = alloca double | ||
| ret void | ||
| } | ||
|
|
||
| ; CHECK: @foo() #1 !sycl_used_aspects ![[#aspects]] | ||
| define spir_kernel void @foo() #1 { | ||
| ret void | ||
| } | ||
|
|
||
| ; CHECK: ![[#aspects]] = !{i32 6} | ||
|
|
||
| attributes #0 = { "indirectly-callable"="_ZTSv" } | ||
| attributes #1 = { "calls-indirectly"="_ZTSv" } | ||
|
|
||
| !sycl_aspects = !{!0} | ||
| !0 = !{!"fp64", i32 6} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| ; RUN: opt -passes=sycl-propagate-aspects-usage < %s -S | FileCheck %s | ||
|
|
||
| %Foo = type { i32 } | ||
| %Bar = type { i32 } | ||
|
|
||
| ; CHECK: @vfnFoo() #0 !sycl_used_aspects ![[#aspectsFoo:]] | ||
| define spir_func void @vfnFoo() #0 { | ||
| %tmp = alloca %Foo | ||
| ret void | ||
| } | ||
|
|
||
| ; CHECK: @vfnBar() #1 !sycl_used_aspects ![[#aspectsBar:]] | ||
| define spir_func void @vfnBar() #1 { | ||
| %tmp = alloca %Bar | ||
| ret void | ||
| } | ||
|
|
||
| ; CHECK: @kernel() #2 !sycl_used_aspects ![[#aspectsKernel:]] | ||
| define spir_kernel void @kernel() #2 { | ||
| ret void | ||
| } | ||
|
|
||
| ; CHECK: ![[#aspectsFoo]] = !{i32 1} | ||
| ; CHECK: ![[#aspectsBar]] = !{i32 2} | ||
| ; CHECK: ![[#aspectsKernel]] = !{i32 1, i32 2} | ||
|
|
||
| attributes #0 = { "indirectly-callable"="setFoo" } | ||
| attributes #1 = { "indirectly-callable"="setBar" } | ||
| attributes #2 = { "calls-indirectly"="setFoo,setBar" } | ||
|
|
||
| !sycl_aspects = !{!0} | ||
| !0 = !{!"fp64", i32 6} | ||
|
|
||
| !sycl_types_that_use_aspects = !{!1, !2} | ||
| !1 = !{!"Foo", i32 1} | ||
| !2 = !{!"Bar", i32 2} |
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Design doc also states the following:
The idea was to support the case like this one:
That should be true already, because propagating aspects like that would require extra code, but I think that we should add a test to indicate to us that such addition should not be performed. Or, even if it is performed, then it should ignore virtual functions, because they use their own special mechanism. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| ; RUN: opt -passes=sycl-propagate-aspects-usage < %s -S | FileCheck %s | ||
|
|
||
| %Foo = type { i32 } | ||
| %Bar = type { i32 } | ||
|
|
||
| ; CHECK: @vfnFoo() #0 !sycl_used_aspects ![[#aspectsFoo:]] | ||
| define spir_func void @vfnFoo() #0 { | ||
| call void @subFoo() | ||
| ret void | ||
| } | ||
|
|
||
| define spir_func void @subFoo() { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should we check the aspects for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We could, but that part should be already covered by tests for "core" aspects propagation mechanism. Those tests are specially focused on scenarios where a kernel does not use a function directly, but still inherits its aspects, because it uses a "set" where this function belongs to. |
||
| %tmp = alloca %Foo | ||
| ret void | ||
| } | ||
|
|
||
| ; CHECK: @vfnBar() #1 !sycl_used_aspects ![[#aspectsBar:]] | ||
| define spir_func void @vfnBar() #1 { | ||
| call void @subBar() | ||
| ret void | ||
| } | ||
|
|
||
| define spir_func void @subBar() { | ||
| %tmp = alloca %Bar | ||
| ret void | ||
| } | ||
|
|
||
| ; CHECK: @kernelA() #2 !sycl_used_aspects ![[#aspectsFoo]] | ||
| define spir_kernel void @kernelA() #2 { | ||
| ret void | ||
| } | ||
|
|
||
| ; CHECK: @kernelB() #3 !sycl_used_aspects ![[#aspectsBar]] | ||
| define spir_kernel void @kernelB() #3 { | ||
| ret void | ||
| } | ||
|
|
||
| ; CHECK: ![[#aspectsFoo]] = !{i32 1} | ||
| ; CHECK: ![[#aspectsBar]] = !{i32 2} | ||
|
|
||
| attributes #0 = { "indirectly-callable"="setFoo" } | ||
| attributes #1 = { "indirectly-callable"="setBar" } | ||
| attributes #2 = { "calls-indirectly"="setFoo" } | ||
| attributes #3 = { "calls-indirectly"="setBar" } | ||
|
|
||
| !sycl_aspects = !{!0} | ||
| !0 = !{!"fp64", i32 6} | ||
|
|
||
| !sycl_types_that_use_aspects = !{!1, !2} | ||
| !1 = !{!"Foo", i32 1} | ||
| !2 = !{!"Bar", i32 2} | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it won't require refactoring of existing code (due to shared data structures, or functions), I would add
consttoFargument (and everywhere else where it is applicable, i.e. toprocessDeclaredVirtualFunctionSetsarguments as well)