-
Notifications
You must be signed in to change notification settings - Fork 788
[SYCL][sycl-post-link] Implement transformation of sycl-properties annotations #5940
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
Merged
steffenlarsen
merged 4 commits into
intel:sycl
from
steffenlarsen:steffen/sycl_post_link_prop_annot_transform
May 3, 2022
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
93 changes: 93 additions & 0 deletions
93
llvm/test/tools/sycl-post-link/sycl-properties-ptr-annotations.ll
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
; RUN: sycl-post-link --device-globals --ir-output-only -S %s -o %t.ll | ||
; RUN: FileCheck %s -input-file=%t.ll | ||
; | ||
; TODO: Remove --device-globals once other features start using compile-time | ||
; properties. | ||
; | ||
; Tests the translation of "sycl-properties" pointer annotations to pointer | ||
; annotations the SPIR-V translator will produce decorations from. | ||
; NOTE: These use SYCL property meta-names that are currently only intended for | ||
; use in attributes-to-metadata translations, but sycl-post-link does not | ||
; currently make the distinction so we will use them for the purpose of | ||
; testing the transformations. | ||
|
||
target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64" | ||
target triple = "spir64-unknown-unknown" | ||
|
||
%struct.foo = type { i32 addrspace(4)*, i32 addrspace(4)*, i32 addrspace(4)*, i32 addrspace(4)*, i32 addrspace(4)*, i32 addrspace(4)*, i32 addrspace(4)* } | ||
|
||
$_ZTSZ4mainEUlvE_ = comdat any | ||
|
||
@.str = private unnamed_addr constant [16 x i8] c"sycl-properties\00", section "llvm.metadata" | ||
@.str.1 = private unnamed_addr constant [36 x i8] c"sycl-properties-ptr-annotations.cpp\00", section "llvm.metadata" | ||
@.str.2 = private unnamed_addr constant [15 x i8] c"sycl-init-mode\00", section "llvm.metadata" | ||
@.str.3 = private unnamed_addr constant [2 x i8] c"1\00", section "llvm.metadata" | ||
@.str.4 = private unnamed_addr constant [22 x i8] c"sycl-implement-in-csr\00", section "llvm.metadata" | ||
@.str.5 = private unnamed_addr constant [5 x i8] c"true\00", section "llvm.metadata" | ||
@.args = private unnamed_addr constant { [15 x i8]*, [2 x i8]*, [22 x i8]*, [5 x i8]* } { [15 x i8]* @.str.2, [2 x i8]*@.str.3, [22 x i8]* @.str.4, [5 x i8]* @.str.5 }, section "llvm.metadata" | ||
@.args.6 = private unnamed_addr constant { [15 x i8]*, [2 x i8]* } { [15 x i8]* @.str.2, [2 x i8]* @.str.3 }, section "llvm.metadata" | ||
@.args.7 = private unnamed_addr constant { [22 x i8]*, [5 x i8]* } { [22 x i8]* @.str.4, [5 x i8]* @.str.5 }, section "llvm.metadata" | ||
@.args.8 = private unnamed_addr constant { [15 x i8]*, [2 x i8]*, [22 x i8]*, [5 x i8]* } { [15 x i8]* @.str.2, [2 x i8]* @.str.3, [22 x i8]* @.str.4, [5 x i8]* @.str.5 }, section "llvm.metadata" | ||
@.str.9 = private unnamed_addr constant [18 x i8] c"sycl-unrecognized\00", section "llvm.metadata" | ||
@.args.10 = private unnamed_addr constant { [15 x i8]*, [2 x i8]*, [18 x i8]*, i8* } { [15 x i8]* @.str.2, [2 x i8]* @.str.3, [18 x i8]* @.str.9, i8* null }, section "llvm.metadata" | ||
@.args.11 = private unnamed_addr constant { [18 x i8]*, i8* } { [18 x i8]* @.str.9, i8* null }, section "llvm.metadata" | ||
|
||
;CHECK: @[[NewAnnotStr1:.*]] = private unnamed_addr constant [24 x i8] c"{6148:\221\22}{6149:\22true\22}\00", section "llvm.metadata" | ||
;CHECK: @[[NewAnnotStr2:.*]] = private unnamed_addr constant [11 x i8] c"{6148:\221\22}\00", section "llvm.metadata" | ||
;CHECK: @[[NewAnnotStr3:.*]] = private unnamed_addr constant [14 x i8] c"{6149:\22true\22}\00", section "llvm.metadata" | ||
|
||
; Function Attrs: mustprogress norecurse | ||
define weak_odr dso_local spir_kernel void @_ZTSZ4mainEUlvE_() local_unnamed_addr #0 comdat !kernel_arg_buffer_location !7 !sycl_kernel_omit_args !7 { | ||
entry: | ||
%x.i = alloca %struct.foo, align 8 | ||
%x.ascast.i = addrspacecast %struct.foo* %x.i to %struct.foo addrspace(4)* | ||
%0 = bitcast %struct.foo* %x.i to i8* | ||
%1 = addrspacecast i8* %0 to i8 addrspace(4)* | ||
%2 = call i8 addrspace(4)* @llvm.ptr.annotation.p4i8(i8 addrspace(4)* %1, i8* getelementptr inbounds ([16 x i8], [16 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([36 x i8], [36 x i8]* @.str.1, i64 0, i64 0), i32 5, i8* bitcast ({ [15 x i8]*, [2 x i8]*, [22 x i8]*, [5 x i8]* }* @.args to i8*)) #2 | ||
; CHECK: %{{.*}} = call i8 addrspace(4)* @llvm.ptr.annotation.p4i8(i8 addrspace(4)* %1, i8* getelementptr inbounds ([24 x i8], [24 x i8]* @[[NewAnnotStr1]], i32 0, i32 0), i8* getelementptr inbounds ([36 x i8], [36 x i8]* @.str.1, i64 0, i64 0), i32 5, i8* null) | ||
%b.i = getelementptr inbounds %struct.foo, %struct.foo addrspace(4)* %x.ascast.i, i64 0, i32 1 | ||
%3 = bitcast i32 addrspace(4)* addrspace(4)* %b.i to i8 addrspace(4)* | ||
%4 = call i8 addrspace(4)* @llvm.ptr.annotation.p4i8(i8 addrspace(4)* %3, i8* getelementptr inbounds ([16 x i8], [16 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([36 x i8], [36 x i8]* @.str.1, i64 0, i64 0), i32 6, i8* bitcast ({ [15 x i8]*, [2 x i8]* }* @.args.6 to i8*)) #2 | ||
; CHECK: %{{.*}} = call i8 addrspace(4)* @llvm.ptr.annotation.p4i8(i8 addrspace(4)* %3, i8* getelementptr inbounds ([11 x i8], [11 x i8]* @[[NewAnnotStr2]], i32 0, i32 0), i8* getelementptr inbounds ([36 x i8], [36 x i8]* @.str.1, i64 0, i64 0), i32 6, i8* null) | ||
%c.i = getelementptr inbounds %struct.foo, %struct.foo addrspace(4)* %x.ascast.i, i64 0, i32 2 | ||
%5 = bitcast i32 addrspace(4)* addrspace(4)* %c.i to i8 addrspace(4)* | ||
%6 = call i8 addrspace(4)* @llvm.ptr.annotation.p4i8(i8 addrspace(4)* %5, i8* getelementptr inbounds ([16 x i8], [16 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([36 x i8], [36 x i8]* @.str.1, i64 0, i64 0), i32 7, i8* bitcast ({ [22 x i8]*, [5 x i8]* }* @.args.7 to i8*)) #2 | ||
; CHECK: %{{.*}} = call i8 addrspace(4)* @llvm.ptr.annotation.p4i8(i8 addrspace(4)* %5, i8* getelementptr inbounds ([14 x i8], [14 x i8]* @[[NewAnnotStr3]], i32 0, i32 0), i8* getelementptr inbounds ([36 x i8], [36 x i8]* @.str.1, i64 0, i64 0), i32 7, i8* null) | ||
%d.i = getelementptr inbounds %struct.foo, %struct.foo addrspace(4)* %x.ascast.i, i64 0, i32 3 | ||
%7 = bitcast i32 addrspace(4)* addrspace(4)* %d.i to i8 addrspace(4)* | ||
%8 = call i8 addrspace(4)* @llvm.ptr.annotation.p4i8(i8 addrspace(4)* %7, i8* getelementptr inbounds ([16 x i8], [16 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([36 x i8], [36 x i8]* @.str.1, i64 0, i64 0), i32 8, i8* bitcast ({ [15 x i8]*, [2 x i8]*, [22 x i8]*, [5 x i8]* }* @.args.8 to i8*)) #2 | ||
; CHECK: %{{.*}} = call i8 addrspace(4)* @llvm.ptr.annotation.p4i8(i8 addrspace(4)* %7, i8* getelementptr inbounds ([24 x i8], [24 x i8]* @[[NewAnnotStr1]], i32 0, i32 0), i8* getelementptr inbounds ([36 x i8], [36 x i8]* @.str.1, i64 0, i64 0), i32 8, i8* null) | ||
%e.i = getelementptr inbounds %struct.foo, %struct.foo addrspace(4)* %x.ascast.i, i64 0, i32 4 | ||
%9 = bitcast i32 addrspace(4)* addrspace(4)* %e.i to i8 addrspace(4)* | ||
%10 = call i8 addrspace(4)* @llvm.ptr.annotation.p4i8(i8 addrspace(4)* %9, i8* getelementptr inbounds ([16 x i8], [16 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([36 x i8], [36 x i8]* @.str.1, i64 0, i64 0), i32 9, i8* bitcast ({ [15 x i8]*, [2 x i8]*, [18 x i8]*, i8* }* @.args.10 to i8*)) #2 | ||
; CHECK: %{{.*}} = call i8 addrspace(4)* @llvm.ptr.annotation.p4i8(i8 addrspace(4)* %9, i8* getelementptr inbounds ([11 x i8], [11 x i8]* @[[NewAnnotStr2]], i32 0, i32 0), i8* getelementptr inbounds ([36 x i8], [36 x i8]* @.str.1, i64 0, i64 0), i32 9, i8* null) | ||
%f.i = getelementptr inbounds %struct.foo, %struct.foo addrspace(4)* %x.ascast.i, i64 0, i32 5 | ||
%11 = bitcast i32 addrspace(4)* addrspace(4)* %f.i to i8 addrspace(4)* | ||
%12 = call i8 addrspace(4)* @llvm.ptr.annotation.p4i8(i8 addrspace(4)* %11, i8* getelementptr inbounds ([16 x i8], [16 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([36 x i8], [36 x i8]* @.str.1, i64 0, i64 0), i32 10, i8* bitcast ({ [18 x i8]*, i8* }* @.args.11 to i8*)) #2 | ||
; CHECK-NOT: %{{.*}} = call i8 addrspace(4)* @llvm.ptr.annotation. | ||
%g.i = getelementptr inbounds %struct.foo, %struct.foo addrspace(4)* %x.ascast.i, i64 0, i32 6 | ||
%13 = bitcast i32 addrspace(4)* addrspace(4)* %g.i to i8 addrspace(4)* | ||
%14 = call i8 addrspace(4)* @llvm.ptr.annotation.p4i8(i8 addrspace(4)* %13, i8* getelementptr inbounds ([16 x i8], [16 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([36 x i8], [36 x i8]* @.str.1, i64 0, i64 0), i32 11, i8* null) #2 | ||
ret void | ||
} | ||
|
||
; Function Attrs: inaccessiblememonly nofree nosync nounwind willreturn | ||
declare i8 addrspace(4)* @llvm.ptr.annotation.p4i8(i8 addrspace(4)*, i8*, i8*, i32, i8*) #1 | ||
|
||
attributes #0 = { mustprogress norecurse "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "sycl-module-id"="sycl-properties-ptr-annotations.cpp" "uniform-work-group-size"="true" } | ||
attributes #1 = { inaccessiblememonly nofree nosync nounwind willreturn } | ||
attributes #2 = { nounwind } | ||
|
||
!opencl.spir.version = !{!0, !0, !0, !0, !0, !0} | ||
!spirv.Source = !{!1, !1, !1, !1, !1, !1} | ||
!llvm.ident = !{!2, !3, !3, !3, !4, !3} | ||
!llvm.module.flags = !{!5, !6} | ||
|
||
!0 = !{i32 1, i32 2} | ||
!1 = !{i32 4, i32 100000} | ||
!2 = !{!"clang version 15.0.0"} | ||
!3 = !{!"clang version 15.0.0"} | ||
!4 = !{!"clang version 15.0.0"} | ||
!5 = !{i32 1, !"wchar_size", i32 4} | ||
!6 = !{i32 7, !"frame-pointer", i32 2} | ||
!7 = !{} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
I'm not sure if this comment is actual now because the pass doesn't just add some metadata anymore. Can rewriting the
@llvm.ptr.annotation
intrinsics have any influence on the analysis?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.
I don't imagine changing the annotation strings of a
llvm.ptr.annotation
with our own "sycl-properties" special-name should affect any analyses. However, I don't know if removing an annotation could affect any previous analyses. @AlexeySachkov - Do you know?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.
@kbobrovs - Do you have some insight into this?
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.
I think we really care if this change can affect transformation (and therefore lead to different IR). Theoretically it could affect subsequent IR t-forms happening before SPIRV generation if they depend on llvm.ptr.annotations (maybe transitively via Analyses). But AFAICS, this is the last tform before SPIRV.
BTW, If this transformation does not require fully linked program, then sycl-post-link would be a wrong place for it. It is always preferable to put additional IR passes to compilation (via BakendUtil.cpp) over putting them into post-link.
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.
At the moment I don't believe it needs a fully linked program, but we could have a similar situation in the future to the
devce_global
where one of the properties need metadata information propagated to the runtime. We could of course create a new representation sycl-post-link would need to look for, but it does complicate the design.Likewise, we would be splitting the property-translation logic, that is some would be done in additional IR pass (annotations -> annotations) while others would be done in sycl-post-link (IR attributes -> metadata). Would there be a good way for the two to share some logic?
@gmlueck - Ping in case you have some opinions on this.
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.
I assume this is the pass that converts
@llvm.ptr.annotation
from the form that contains the property names (strings) into the form that contains SPIR-V decoration numbers? (This follows the design in #5884.) Correct?That pass is part of the general logic for converting LLVM IR into a "SPIR-V friendly form", and I thought we did all of this logic in
sycl-post-link
, just before we translate to SPIR-V. One advantage of this, I suppose, is that we can avoid doing this translation for targets that don't use SPIR-V.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.
This is indeed the implementation of that pass, currently shared with the logic for translating IR attributes.
Since @kbobrovs suggests for the pass to be part of
BackendUtil.cpp
, I believe we should be able to make it an elective pass that is only run when SPIR-V is the target, while other backend targets can use their own pass for the translations. However, fordevice_global
sycl-post-link
still needs to create the unique ID and communicate it to the runtime. We may be able to split the generation of the unique ID and the generation of the corresponding metadata to an earlier IR pass, but in that casesycl-post-link
would have to parse the "SPIR-V friendly" metadata and base the information for the runtime on that.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.
Isn't this a reason not to move the translation to "SPIR-V friendly" form to
BackendUtil.cpp
? If we did this, thensycl-post-link
needs to understand either the SPIR-V friendly form or the normal LLVM IR form (depending on whether the target supports SPIR-V)?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.
Either that, or we would make a common part of the pass (or another pass) that adds some new information that sycl-post-link will consume. It does complicate the design, but it would make backend-specific parsing of properties easier.
Either way, I think it should be considered for the entire pass rather than the changes made in this. @kbobrovs do you think there would be a problem in going with it as part of sycl-post-link for now and then discuss the transition to
BackendUtil.cpp
separately?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.
@steffenlarsen, I think transition to BackendUtil.cpp should be discussed separately, my comment was not meant to hold this PR.
A note about BackendUtil.cpp vs sycl-post-link.cpp. The original intent of
sycl-post-link
was to perform transformations which can not be done w/o knowing the entire program - such as assigning specialization constant IDs. The more transformations are implemented in sycl-post-link, the farther SYCL is from other compilers many of which don't even use any additional link-time IR transformations by default. It is like having a "hidden pass manager" in the form of thesycl-post-link
, which bypasses clang optimization/transformation control mechanisms. There are some other disadvantages: extra link time (important for device libraries, which get compiled once and linked many times), compiler developers need to run post-link to see final code before SPIRV.