Skip to content

[SYCL][Doc] Adjust design for compile-time properties through add_ir_annotations_member #5884

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
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
133 changes: 87 additions & 46 deletions sycl/doc/design/CompileTimeProperties.md
Original file line number Diff line number Diff line change
Expand Up @@ -465,25 +465,50 @@ When the device compiler generates code to reference the decorated member
variable, it emits a call to the LLVM intrinsic function
[`@llvm.ptr.annotation`][10] that annotates the pointer to that member
variables, similar to the way the existing `[[clang::annotate()]]` attribute
works. Illustrating this with some simplified LLVM IR that matches the example
code above:
works.

[10]: <https://llvm.org/docs/LangRef.html#llvm-ptr-annotation-intrinsic>

The front-end encodes the properties from the C++ attribute
`[[__sycl_detail__::add_ir_annotations_member()]]` into the
`@llvm.ptr.annotation` call as follows:

* The first parameter to `@llvm.ptr.annotation` is the pointer to annotate (as
with any call to this intrinsic).
* The second parameter is the literal string `"sycl-properties"`.
* The third parameter is the name of the source file (as with any call to this
intrinsic).
* The fourth parameter is the line number (as with any call to this intrinsic).
* The fifth parameter is a pointer to a constant global variable. The type of
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it allowed adding parameters to the @llvm.ptr.annotation intrinsic? In the LangRef only 4 parameters are described.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is curious. According to the intrinsic definition in Intrinsics.td it has 5 parameters, the last being another i8 *. It does not seem to be a recent change so I think maybe someone forgot to update the LangRef?

this variable is an anonymous structure. The first field of the structure is
a pointer to a string literal representing the name of the first property. The
second field of the structure is a pointer to a string literal representing
the value of the first property. The third field of the structure is a pointer
to a string literal representing the name of the second property, etc.
Since each property has exactly one value, this tuple has an even number of
elements. Pointers to property value strings may be a null-pointer, signalling
a property without a value.

The resulting LLVM IR for the previous example would be:

```
@.str = private unnamed_addr constant [16 x i8] c"sycl-properties\00",
section "llvm.metadata"
@.str.1 = private unnamed_addr constant [9 x i8] c"file.cpp\00",
section "llvm.metadata"
@.str.2 = private unnamed_addr constant [9 x i8] c"sycl-foo\00", align 1
@.str.3 = private unnamed_addr constant [9 x i8] c"sycl-bar\00", align 1
@.str.2 = private unnamed_addr constant [9 x i8] c"sycl-foo\00",
section "llvm.metadata"
@.str.3 = private unnamed_addr constant [9 x i8] c"sycl-bar\00",
section "llvm.metadata"
@.str.4 = private unnamed_addr constant [3 x i8] c"32\00",
section "llvm.metadata"

@.args = private unnamed_addr constant { [9 x i8]*, i8*, [9 x i8]*, i32 }
@.args = private unnamed_addr constant { [9 x i8]*, i8*, [9 x i8]*, [3 x i8]* }
{
[9 x i8]* @.str.2, ; Name of first property "sycl-foo"
i8* null, ; Null indicates this property has no value
[9 x i8]* @.str.3, ; Name of second property "sycl-bar"
i32 32 ; Value of second property
[3 x i8]* @.str.4 ; Value of second property
},
section "llvm.metadata"

Expand All @@ -497,31 +522,14 @@ define void @foo(i32* %ptr) {
i8* getelementptr inbounds ([16 x i8], [16 x i8]* @.str, i64 0, i64 0),
i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str.1, i64 0, i64 0),
i32 3,
i8* bitcast ({ [9 x i8]*, i8*, [9 x i8]*, i32 }* @.args to i8*))
i8* bitcast ({ [9 x i8]*, i8*, [9 x i8]*, [3 x i8]* }* @.args to i8*))

%3 = bitcast i8* %2 to i32**
store i32* %ptr, i32** %3
ret void
}
```

The front-end encodes the properties from the C++ attribute
`[[__sycl_detail__::add_ir_annotations_member()]]` into the
`@llvm.ptr.annotation` call as follows:

* The first parameter to `@llvm.ptr.annotation` is the pointer to annotate (as
with any call to this intrinsic).
* The second parameter is the literal string `"sycl-properties"`.
* The third parameter is the name of the source file (as with any call to this
intrinsic).
* The fourth parameter is the line number (as with any call to this intrinsic).
* The fifth parameter is a metadata tuple with information about all of the
properties. The first element of the tuple is a string literal with the name
of the first property. The second element is the value of the first
property. The third element is a string literal with the name of the second
property, etc. Since each property has exactly one value, this tuple has an
even number of elements.

**NOTE**: Calls to the `@llvm.ptr.annotation` intrinsic function are known to
disable many clang optimizations. As a result, properties added to a
non-global variable will likely result in LLVM IR (and SPIR-V) that is not well
Expand Down Expand Up @@ -597,18 +605,20 @@ types listed above.

Properties that are implemented using
`[[__sycl_detail__::add_ir_annotations_member()]]`, are represented in LLVM IR
as the fifth metadata parameter to the `@llvm.ptr.annotation` intrinsic
function. This parameter is a tuple of metadata values with the following
sequence:
as the fifth parameter to the `@llvm.ptr.annotation` intrinsic function. This
parameter is a pointer to a global variable with fields corresponding to the
names and values of the properties in the following sequence:

* Name of the first property
* Value of the first property
* Name of the second property
* Value of the second property
* Etc.

Since metadata types are not limited to strings, there is no need to convert
the property values to strings.
Every field in the global variable pointed to by this parameter are string
literals in seperate global variables. Property values are converted to strings
in the same way as described above, except that the `nullptr` value and the
empty string (`""`) is represented as `null` in the global variable field.


## Filtering properties
Expand Down Expand Up @@ -806,26 +816,57 @@ into one (or both) of the following:
In both cases, the decoration is a single **UserSemantic** decoration where the
string literal is the same as the string literal in the LLVM annotation.

When a SYCL structure member property needs to be represented in SPIR-V,
however, we prefer to represent each property as an extended SPIR-V decoration
rather than using a **UserSemantic** decoration. There is no existing
mechanism in the SPIR-V LLVM Translator to generate extended decorations like
this, so we propose the following new mechanism.
An exception to this is for a selection of FPGA-related decorations. If these
are supported during translation from LLVM IR to SPIR-V the corresponding
decorations will be generated, and otherwise it will fall back to creating a
single **UserSemantic** decoration. In general these decorations occur in the
annotation string as a series of **{X}** and **{X:Y}** where **X** is a reserved
name and **Y** is one or more words and numbers separated by a comma (**,**) or
a colon (**:**), depending on the decoration.

As such we propose an extension to this functionality with the following
changes:

* To bring it in line with the format of the metadata decorations, the parsing
of these decorations should allow the use of SPIR-V decoration identifiers
rather than reserved names. With this there need not be any agreement between
the translator and LLVM IR producer, as the identifiers are specified by the
SPIR-V specification.
* For decorations parsed with decoration identifiers, only the comma delimiter
is valid for separating decoration values.
* In addition to words and numbers, string literals enclosed by quotation marks
are allowed as decoration values. No escapes are planned for this, so all
symbols between starting quotation mark and ending quotation mark are
considered part of the string literal.

When a member variable property needs to be represented in SPIR-V, the
`sycl-post-link` tool converts the `@llvm.ptr.annotation` intrinsic call into a
call to the SPIR-V intrinsic `__spirv_AddMemberDecoration` which has a metadata
function argument that specifies the decorations as illustrated below:
`sycl-post-link` tool converts the `@llvm.ptr.annotation` intrinsic call
produced by `[[__sycl_detail__::add_ir_annotations_member()]]` into another
`@llvm.ptr.annotation` intrinsic call using this format. For example:

```
%annotated_ptr = call i8* __spirv_AddMemberDecoration(i8* %ptr, metadata !0)
; Contains decorations:
; * 7744 with no value.
; * 7745 with 20 and "str 1" as the values.
@.str = private unnamed_addr constant [24 x i8] c"{7744}{7745:20,\22str 1\22}\00",
section "llvm.metadata"
@.str.1 = private unnamed_addr constant [9 x i8] c"file.cpp\00",
section "llvm.metadata"

!0 = !{!1, !2} ; Each operand in this metadata represents one
; decoration.
!1 = !{i32 7744} ; This is the integer value of the first decoration.
!2 = !{i32 7745, i32 20} ; The first operand is the integer value of the
; second decoration. Additional operands are
; "extra operands" to the decoration. These
; operands may be either integer literals or string
; literals.
define void @foo(i32* %ptr) {
...

; %0 points to the annotated member field.
%2 = call i8* @llvm.ptr.annotation.p0i8(i8* nonnull %0,
i8* getelementptr inbounds ([16 x i8], [16 x i8]* @.str, i64 0, i64 0),
i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str.1, i64 0, i64 0),
i32 3,
i8* null)

...
}
```

**NOTE**: To allow backwards compatibility with the old format, reverse
translation of decorations will produce a decorations in the annotation string
following the old format if the decoration had a reserved name.