@@ -88,10 +88,13 @@ class
88
88
} // namespace sycl::ext::oneapi
89
89
```
90
90
91
- The initial entries in the C++ attribute's parameter list are the names of the
92
- properties, and these are followed by the values of the properties. To
93
- illustrate using the same example as before, the result of the parameter pack
94
- expansion would look like this:
91
+ The ` [[__sycl_detail__::add_ir_global_variable_attributes()]] ` attribute has an
92
+ even number of parameters. The first half of the parameters are the names of
93
+ the properties, and the second half of the parameters are the values for those
94
+ properties. Each property has exactly one value, so the property at parameter
95
+ position 0 corresponds to the value at position _ N / 2_ , etc. To illustrate
96
+ using the same example as before, the result of the parameter pack expansion
97
+ would look like this:
95
98
96
99
```
97
100
namespace sycl::ext::oneapi {
@@ -101,7 +104,7 @@ template </* ... */> class
101
104
[[__sycl_detail__::add_ir_global_variable_attributes(
102
105
"sycl-device-image-scope", // Name of first property
103
106
"sycl-host-access", // Name of second property
104
- "", // First property has no parameter
107
+ nullptr, // First property has no parameter
105
108
"read" // Value of second property
106
109
)]]
107
110
#endif
@@ -128,10 +131,10 @@ type as described above, it also adds one IR attribute to the global variable
128
131
for each property using
129
132
[ ` GlobalVariable::addAttribute(StringRef, StringRef) ` ] [ 4 ] . If the property
130
133
value is not already a string, it converts it to a string as described in
131
- [ Property representation in C++ attributes] [ 5 ] .
134
+ [ IR representation as IR attributes] [ 5 ] .
132
135
133
136
[ 4 ] : < https://llvm.org/doxygen/classllvm_1_1GlobalVariable.html#a6cee3c634aa5de8c51e6eaa4e41898bc >
134
- [ 5 ] : < #property -representation-in-C -attributes >
137
+ [ 5 ] : < #ir -representation-as-ir -attributes >
135
138
136
139
Note that the front-end does not need to understand any of the properties in
137
140
order to do this translation.
@@ -219,7 +222,7 @@ template </* ... */> class
219
222
[[__sycl_detail__::add_ir_kernel_parameter_attributes(
220
223
"sycl-no-alias", // Name of first property
221
224
"sycl-foo", // Name of second property
222
- "", // First property has no parameter
225
+ nullptr, // First property has no parameter
223
226
32 // Value of second property
224
227
)]]
225
228
#endif
@@ -423,10 +426,10 @@ class annotated_ptr<T, property_list<Props...>> {
423
426
T *ptr
424
427
#ifdef __SYCL_DEVICE_ONLY__
425
428
[[__sycl_detail__::add_ir_member_annotation(
426
- "foo", // Name of first property
427
- "bar", // Name of second property
428
- "", // First property has no parameter
429
- 32 // Value of second property
429
+ "sycl- foo", // Name of first property
430
+ "sycl- bar", // Name of second property
431
+ nullptr, // First property has no parameter
432
+ 32 // Value of second property
430
433
)]]
431
434
#endif
432
435
;
@@ -440,48 +443,63 @@ class annotated_ptr<T, property_list<Props...>> {
440
443
When the device compiler generates code to reference the decorated member
441
444
variable, it emits a call to the LLVM intrinsic function
442
445
[ ` @llvm.ptr.annotation ` ] [ 10 ] that annotates the pointer to that member
443
- variables, similar to the way the existing clang ` __attribute__(( annotate())) `
446
+ variables, similar to the way the existing ` [[clang:: annotate()]] ` attribute
444
447
works. Illustrating this with some simplified LLVM IR that matches the example
445
448
code above:
446
449
447
450
[ 10 ] : < https://llvm.org/docs/LangRef.html#llvm-ptr-annotation-intrinsic >
448
451
449
452
```
450
- @.str = private unnamed_addr constant [27 x i8] c"sycl-properties:foo,bar=32 \00",
451
- section "llvm.metadata"
453
+ @.str = private unnamed_addr constant [16 x i8] c"sycl-properties\00",
454
+ section "llvm.metadata"
452
455
@.str.1 = private unnamed_addr constant [9 x i8] c"file.cpp\00",
453
- section "llvm.metadata"
456
+ section "llvm.metadata"
457
+ @.str.2 = private unnamed_addr constant [9 x i8] c"sycl-foo\00", align 1
458
+ @.str.3 = private unnamed_addr constant [9 x i8] c"sycl-bar\00", align 1
459
+
460
+ @.args = private unnamed_addr constant { [9 x i8]*, i8*, [9 x i8]*, i32 }
461
+ {
462
+ [9 x i8]* @.str.2, ; Name of first property "sycl-foo"
463
+ i8* null, ; Null indicates this property has no value
464
+ [9 x i8]* @.str.3, ; Name of second property "sycl-bar"
465
+ i32 32 ; Value of second property
466
+ },
467
+ section "llvm.metadata"
454
468
455
469
define void @foo(i32* %ptr) {
456
470
%aptr = alloca %class.annotated_ptr
457
471
%ptr = getelementptr inbounds %class.annotated_ptr, %class.annotated_ptr* %aptr,
458
472
i32 0, i32 0
459
473
%1 = bitcast i32** %ptr to i8*
460
- %2 = call i8* @llvm.ptr.annotation.p0i8(i8* %1,
461
- i8* getelementptr inbounds ([27 x i8], [27 x i8]* @.str, i32 0, i32 0),
462
- i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str.1, i32 0, i32 0),
463
- i32 3, i8* null)
474
+
475
+ %2 = call i8* @llvm.ptr.annotation.p0i8(i8* nonnull %0,
476
+ i8* getelementptr inbounds ([16 x i8], [16 x i8]* @.str, i64 0, i64 0),
477
+ i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str.1, i64 0, i64 0),
478
+ i32 3,
479
+ i8* bitcast ({ [9 x i8]*, i8*, [9 x i8]*, i32 }* @.args to i8*))
480
+
464
481
%3 = bitcast i8* %2 to i32**
465
482
store i32* %ptr, i32** %3
466
483
ret void
467
484
}
468
485
```
469
486
470
487
The front-end encodes the properties from the C++ attribute
471
- ` [[__sycl_detail__::add_ir_member_annotation()]] ` into the annotation string
472
- (` @.str ` in the example above) using the following algorithm:
473
-
474
- * The property value is converted to a string as specified in
475
- [ Property representation in C++ attributes] [ 5 ] .
476
- * Construct a property definition string for each property:
477
- - If the property value is the empty string, the property definition is just
478
- the name of the property.
479
- - Otherwise, the property definition string is formed by concatenating the
480
- property name with the equal sign (` = ` ) and the property value.
481
- * The annotation string is formed by concatenating all property definition
482
- strings, separated by a comma (` , ` ).
483
- * The annotation string is pre-pended with ` "sycl-properties:" ` and NULL
484
- terminated.
488
+ ` [[__sycl_detail__::add_ir_member_annotation()]] ` into the
489
+ ` @llvm.ptr.annotation ` call as follows:
490
+
491
+ * The first parameter to ` @llvm.ptr.annotation ` is the pointer to annotate (as
492
+ with any call to this intrinsic).
493
+ * The second parameter is the literal string ` "sycl-properties" ` .
494
+ * The third parameter is the name of the source file (as with any call to this
495
+ intrinsic).
496
+ * The fourth parameter is the line number (as with any call to this intrinsic).
497
+ * The fifth parameter is a metadata tuple with information about all of the
498
+ properties. The first element of the tuple is a string literal with the name
499
+ of the first property. The second element is the value of the first
500
+ property. The third element is a string literal with the name of the second
501
+ property, etc. Since each property has exactly one value, this tuple has an
502
+ even number of elements.
485
503
486
504
** NOTE** : Calls to the ` @llvm.ptr.annotation ` intrinsic function are known to
487
505
disable many clang optimizations. As a result, properties added to a
@@ -490,7 +508,7 @@ optimized. This puts more pressure on the SPIR-V consumer (e.g. JIT compiler)
490
508
to perform these optimizations.
491
509
492
510
493
- ## Property representation in C++ attributes
511
+ ## Property representation in C++ attributes and in IR
494
512
495
513
As noted above, there are several C++ attributes that convey property names and
496
514
values to the front-end:
@@ -502,11 +520,12 @@ values to the front-end:
502
520
503
521
All of these attributes take a parameter list with the same format. There are
504
522
always an even number of parameters, where the first half are the property
505
- names and the second half are the property values. The property name is always
506
- a string literal or a ` constexpr char * ` expression. By convention, property
507
- names that correspond to LLVM IR attributes normally start with the prefix
508
- ` "sycl-" ` in order to avoid collision with non-SYCL IR attributes, but this is
509
- not a strict requirement.
523
+ names and the second half are the property values. (This assumes that the
524
+ initial optional parameter is not passed. See below for a description of this
525
+ optional parameter.) The property name is always a string literal or a
526
+ ` constexpr char * ` expression. By convention, property names normally start
527
+ with the prefix ` "sycl-" ` in order to avoid collision with non-SYCL IR
528
+ attributes, but this is not a strict requirement.
510
529
511
530
The property value can be a literal or ` constexpr ` expression of the following
512
531
types:
@@ -517,15 +536,29 @@ types:
517
536
* A boolean type.
518
537
* A character type.
519
538
* An enumeration type.
539
+ * ` nullptr_t ` (reserved for the case when a property has no value).
520
540
521
541
All properties require a value when represented in the C++ attribute. If the
522
- SYCL property has no value the header passes the empty string (` "" ` ).
542
+ SYCL property has no value the header passes ` nullptr ` .
543
+
544
+ ### IR representation as IR attributes
545
+
546
+ Properties that are implemented using the following C++ attributes are
547
+ represented in LLVM IR as IR attributes:
523
548
524
- The front-end converts each value to a string before representing it in LLVM
525
- IR. Integer and floating point values are converted with the same format as
526
- ` std::to_string() ` would produce. Boolean values are converted to either
527
- ` "true" ` or ` "false" ` . Enumeration values are first converted to an integer
528
- and then converted to a string with the same format as ` std::to_string() ` .
549
+ * ` [[__sycl_detail__::add_ir_global_variable_attributes()]] `
550
+ * ` [[__sycl_detail__::add_ir_kernel_parameter_attributes()]] `
551
+ * ` [[__sycl_detail__::add_ir_function_attributes()]] `
552
+
553
+ When the front-end consumes these C++ attributes and produces IR, each property
554
+ name becomes an IR attribute name and each property value becomes the
555
+ attribute's value. Because the attribute values must be strings, the front-end
556
+ converts each property value to a string. Integer and floating point values
557
+ are converted with the same format as ` std::to_string() ` would produce.
558
+ Boolean values are converted to either ` "true" ` or ` "false" ` . Enumeration
559
+ values are first converted to an integer and then converted to a string with
560
+ the same format as ` std::to_string() ` . The ` nullptr ` value is converted to an
561
+ empty string (` "" ` ).
529
562
530
563
** TODO** : Should we allow property values that are type names? If so, I
531
564
suppose they would be converted to a string representation of the mangled name?
@@ -539,6 +572,94 @@ we do not allow non-fundamental types, how do we represent properties like
539
572
allow ` std::tuple ` , where the type of each element is one of the fundamental
540
573
types listed above.
541
574
575
+ ### IR representation via ` @llvm.ptr.annotation `
576
+
577
+ Properties that are implemented using
578
+ ` [[__sycl_detail__::add_ir_member_annotation()]] ` , are represented in LLVM IR
579
+ as the fifth metadata parameter to the ` @llvm.ptr.annotation ` intrinsic
580
+ function. This parameter is a tuple of metadata values with the following
581
+ sequence:
582
+
583
+ * Name of the first property
584
+ * Value of the first property
585
+ * Name of the second property
586
+ * Value of the second property
587
+ * Etc.
588
+
589
+ Since metadata types are not limited to strings, there is no need to convert
590
+ the property values to strings.
591
+
592
+
593
+ ## Filtering properties
594
+
595
+ It is sometimes necessary to filter out certain properties so that only a
596
+ subset of the properties in a list are represented in IR. There are two
597
+ scenarios when this is useful.
598
+
599
+ In some cases, a property is used only in the header file itself, and there is
600
+ no need to represent that property in LLVM IR. In order to avoid cluttering
601
+ the IR with unneeded information, these properties can be "filtered out", so
602
+ that the front-end does not generate an IR representation.
603
+
604
+ Another case is when a class wants to represent some properties one way in the
605
+ IR while representing other properties in another way. For example, a future
606
+ version of ` accessor ` might pass some properties to
607
+ ` [[__sycl_detail__::add_ir_kernel_parameter_attributes()]] ` while passing other
608
+ properties to ` [[__sycl_detail__::add_ir_member_annotation()]] ` . Again, the
609
+ header wants some way to "filter" the properties, such that some properties are
610
+ interpreted as "kernel parameter attributes" while other are interpreted as
611
+ "member annotations".
612
+
613
+ To handle these cases, each of the following C++ attributes takes an optional
614
+ first parameter that is a brace-enclosed list of property names:
615
+
616
+ * ` [[__sycl_detail__::add_ir_global_variable_attributes()]] `
617
+ * ` [[__sycl_detail__::add_ir_kernel_parameter_attributes()]] `
618
+ * ` [[__sycl_detail__::add_ir_function_attributes()]] `
619
+ * ` [[__sycl_detail__::add_ir_member_annotation()]] `
620
+
621
+ The front-end treats this list as a "pass list", ignoring any property whose
622
+ name is not in the list. To illustrate, consider the following example where
623
+ ` accessor ` treats some properties as "kernel parameter attributes" and others
624
+ as "member annotations":
625
+
626
+ ```
627
+ template <typename dataT,
628
+ int dimensions,
629
+ access::mode accessmode,
630
+ access::target accessTarget,
631
+ access::placeholder isPlaceholder,
632
+ typename ...Props>
633
+ class
634
+ #ifdef __SYCL_DEVICE_ONLY__
635
+ [[__sycl_detail__::add_ir_kernel_parameter_attributes(
636
+
637
+ // The properties in this list are "kernel parameter attributes".
638
+ {"sycl-no-alias", "sycl-foo"},
639
+
640
+ Props::meta_name..., Props::meta_value...
641
+ )]]
642
+ #endif
643
+ accessor<dataT,
644
+ dimensions,
645
+ accessmode,
646
+ accessTarget,
647
+ isPlaceholder,
648
+ property_list<Props...>> {
649
+ T *ptr
650
+ #ifdef __SYCL_DEVICE_ONLY__
651
+ [[__sycl_detail__::add_ir_member_annotation(
652
+
653
+ // The properties in this list are "member annotations".
654
+ {"sycl-bar"},
655
+
656
+ Props::meta_name..., Props::meta_value...
657
+ )]]
658
+ #endif
659
+ ;
660
+ }
661
+ ```
662
+
542
663
543
664
## Representing properties in SPIR-V
544
665
@@ -638,7 +759,8 @@ of the global variable's decorations. To illustrate:
638
759
639
760
As we noted earlier, a property on a structure member variable is represented
640
761
in LLVM IR as a call to the intrinsic function ` @llvm.ptr.annotation ` , where
641
- the annotation string starts with the prefix ` "sycl-properties:" ` . In order to
762
+ the annotation string is ` "sycl-properties" ` and the properties are represented
763
+ as metadata in the fifth parameter to ` @llvm.ptr.annotation ` . In order to
642
764
understand how these SYCL properties are translated into SPIR-V, it's useful to
643
765
review how a normal (i.e. non-SYCL) call to ` @llvm.ptr.annotation ` is
644
766
translated.
0 commit comments