From 453683bf44f2112719802eaac2b332d49eebd640 Mon Sep 17 00:00:00 2001 From: Yong He Date: Mon, 19 Aug 2024 15:03:56 -0700 Subject: Tuple swizzling, concat, comparison and `countof`. (#4856) * Tuple swizzling and element access. * Update proposal status. * Cleanup. * Fix merrge error. * Address review. --- docs/proposals/007-variadic-generics.md | 32 ++++++++++---------- docs/proposals/008-tuples.md | 25 +++++++++------- docs/user-guide/03-convenience-features.md | 47 ++++++++++++++++++++++++++++++ docs/user-guide/toc.html | 1 + 4 files changed, 79 insertions(+), 26 deletions(-) (limited to 'docs') diff --git a/docs/proposals/007-variadic-generics.md b/docs/proposals/007-variadic-generics.md index 65c8fd0c7..ed2754183 100644 --- a/docs/proposals/007-variadic-generics.md +++ b/docs/proposals/007-variadic-generics.md @@ -13,14 +13,15 @@ written in native Slang code rather than on top of it with macros or custom code Status ------ -Status: Implementation in-progress. +Status: Implemented. Author: Yong He. Implementation: [PR 4833](https://github.com/shader-slang/slang/pull/4833), [PR 4849](https://github.com/shader-slang/slang/pull/4849), - [PR 4850](https://github.com/shader-slang/slang/pull/4850) + [PR 4850](https://github.com/shader-slang/slang/pull/4850), + [PR 4856](https://github.com/shader-slang/slang/pull/4856) Reviewed by: Kai Zhang, Jay Kwak, Ariel Glasroth. @@ -239,6 +240,9 @@ The most general case of a type pack is defined by the `expand PatternExpr` type abstract type pack that can be evaluated by substituting all `each X` expressions in the `PatternExpr` with a corresponding element in `X`, and joining all the resulting element types into a type pack. +Note that a `ConcreteTypePack` is very similar in semantic meaning to a `Tuple`, with the exception that `ConcreteTypePack` also bears the automatic flattening semantic, such that +`ConcreteTypePack(ConcreteTypePack(a,b), c)` is equivalent and can be simplified to `ConcreteTypePack(a,b,c)`. + In summary, a type pack can be represented by one of: - `ConcreteTypePack`, a simple concrete list of element types. - `DeclRefType(GenericTypePackParameterDecl)`, a simple reference to a generic type pack parameter. @@ -510,15 +514,11 @@ f(3, Pack(Foo(), Bar()), Pack(1.0f, false)) After resolving the call. The `Pack(...)` represents the `PackExpr` synthesized by the compiler to create a `ValuePack` whose type is a `TypePack`, so it can be used as argument to a `TypePack` parameter. -To help with understanding, a `TypePack(T0, T1, ... Tn)` can be thought as a `Tuple` type, and a `PackExpr(v0, v1, ... vn)` is an operation that -creates a tuple from the values of `v0, v1, ... vn`. The reason we are not referring them as tuple types directly is because we want to distinguish the compiler-synthesized -type packs from the user defined tuple types/tuple values when we introduce tuple types in the standard library in the future. - ### IR Representation #### Expressing Types -A concrete type pack is represented as `IRTupleType(T0, T1, ..., Tn)` in the IR, and an abstract type pack such as an `expand` type will eventually be specialized into an `IRTupleType`. This means that a function parameter whose type is a type pack is translated into a single parameter with an equivalent tuple type. In fact, there is no real semantic difference between a tuple type and a type pack, and the reason that we distinguish type packs from tuple types in the frontend is to avoid ambiguity between a user-defined tuple and a compiler-synthesized type pack. Once we are in the IR, there is no more reason to treat them as separate types. +A concrete type pack is represented as `IRTypePack(T0, T1, ..., Tn)` in the IR, and an abstract type pack such as an `expand` type will eventually be specialized into an `IRTypePack`. This means that a function parameter whose type is a type pack is translated into a single parameter of `IRTypePack` type. Again, `IRTypePack` is in many ways similar to `IRTupleType`, except that `IRTypePack` are automatically flattened into enclosing type packs during specialization. We will represent `expand` and `each` types in the IR almost 1:1 as they are represented in the AST. Note that types are hoistable insts in Slang IR and is globally deduplicated based on their operands, representing it in the natural way will allow these types to take advantage from Slang IR's global deduplication service. @@ -539,10 +539,10 @@ For example, the type `expand vector`, where `T` and `U` are gen #### Expressing Values -A value whose type is a type pack is called a value pack. A value pack is represented in the IR as a tuple. +A value whose type is a type pack is called a value pack. A value pack is represented in the IR as a `IRMakeValuePack` inst. For example, the value pack `(1,2,3)` will be represented in the IR as: ``` -IRMakeTuple(1,2,3) : IRTupleType(int, int, int) +IRMakeValuePack(1,2,3) : IRTypePack(int, int, int) ``` An `expand(PatternExpr)` expression should be represented in the IR as: @@ -564,7 +564,7 @@ For example, given `v` as value pack whose type is a type pack, `let x = expand ``` %v = /*some value pack whose type is a TypePack*/ -%x = IRExpand : IRTuple(...) +%x = IRExpand : IRTypePack(...) { IRBlock { @@ -615,7 +615,7 @@ all references to `IRParam` with the concrete index for the copy. Therefore, spe ``` Step 2 is to hookup each copied blocks by replacing all the `yield` instructions with `branch` instructions, and form the final result of the value pack -by packing up all the values computed at each "loop iteration" in an `IRMakeTuple` inst: +by packing up all the values computed at each "loop iteration" in an `IRMakeValuePack` inst: ``` %block0 = IRBlock @@ -638,17 +638,17 @@ by packing up all the values computed at each "loop iteration" in an `IRMakeTupl } %mergeBlock = IRBlock { - %expand = IRMakeTuple(%r0, %r1, %r2); + %expand = IRMakeValuePack(%r0, %r1, %r2); } ``` With this, we can replace the original `IRExpand` inst with `%expand` and specailization is done. The specialized instructions like `IRGetTupleElement(%v, 0)` will be picked up -in the follow-up step during specalization and replaced with the actual value at the specified index since `%v` is a known value pack represented by `IRMakeTuple`. So after +in the follow-up step during specalization and replaced with the actual value at the specified index since `%v` is a known value pack represented by `IRMakeValuePack`. So after folding and other simplifications, we should result in ``` -%expand = IRMakeTuple(2,3,4) +%expand = IRMakeValuePack(2,3,4) ``` -When specializing the original expression with `IRMakeTuple(1,2,3)` in the IR. +When specializing the original expression with `IRMakeValuePack(1,2,3)` in the IR. Specialization of types and witness follows the same idea of value specialization, but since types and witnesses are represented directly as ordinary insts and operands instead of the nested children of an `IRExpand`, we will use a recursive process on the type structure to perform the specialization. Most of the recursion logic should be trivial, and the only @@ -656,6 +656,8 @@ interesting case is when specializing `IRExpandType` and `IREachType`. During th index when specializing the pattern type of an `IRExpandType`, and then when we get to specialize an `IREachType(TPack)`, we should know which index in the pack we are currently expanding by looking at the `indexInPack` context variable, and replace `IREachType(TypePack(T0, T1, ... Tn))` with the `T` at `indexInPack`. +After the specialization pass, there should be no more `IRExpand` and `IRExpandType` instructions in the IR. And we can lower t he remaining `IRTypePack` the same way as `IRTupleType`s. + Alternatives Considered ----------------------- diff --git a/docs/proposals/008-tuples.md b/docs/proposals/008-tuples.md index b1e62596f..efbcb7d28 100644 --- a/docs/proposals/008-tuples.md +++ b/docs/proposals/008-tuples.md @@ -11,9 +11,11 @@ Status Author: Yong He -Implementation: In-progress. +Status: Implemented. -Reviewed by: N/A +Implementation: [PR 4856](https://github.com/shader-slang/slang/pull/4856). + +Reviewed by: Jay Kwak, Kai Zhang, Ariel Glasroth. Background ---------- @@ -32,7 +34,7 @@ __generic __magic_type(TupleType) struct Tuple { - __intrinsic_op($(0)) + __intrinsic_op($(kIROp_MakeTuple)) __init(expand each T); } ``` @@ -77,15 +79,8 @@ Tuple concat(Tuple { return makeTuple(expand each first, expand each second); } -Tuple concat(Tuple first, expand each U second) -{ - return makeTuple(expand each first, expand each second); -} ``` -Note that we can't have an overload that takes a type pack and append it to the beginning of a tuple yet, because we -currently don't support having type pack arguments that aren't at the end of an argument list. - ### Counting @@ -134,4 +129,12 @@ Should we automatically treat `Tuple` type to conform to any interface `IFoo` if `IFoo`? We can't because this is not well-defined. For example, if `IFoo` has a method that returns `int`, should the tuple type's equivalent method return `Tuple` or just `int`? In some cases you want one but other times you want the other. And if the method returns a tuple, it is no longer consistent with the base interface -definition so this is all ill-formed. \ No newline at end of file +definition so this is all ill-formed. + +We also considered having an overload of `concat` that appends individual elements to the end of a tuple, such as: +``` +Tuple concat(Tuple t, each U values); +``` +However, this could lead to surprising behavior when the user writes `concat(t0, t1, t2)` where t1 and t2 are also tuples. +Having this overload means the result would be `(t0_0, t0_1, ... t0_n, t1, t2)` where the user could be expecting `t1` and `t2` +to be flattened into the resulting tuple. To avoid this surprising behavior, we decide to not include this overload in stdlib. \ No newline at end of file diff --git a/docs/user-guide/03-convenience-features.md b/docs/user-guide/03-convenience-features.md index dc1723ebe..559e4c9b4 100644 --- a/docs/user-guide/03-convenience-features.md +++ b/docs/user-guide/03-convenience-features.md @@ -354,6 +354,53 @@ int test() } ``` +## Tuple Types + +Tuple types can hold collection of values of different types. +Tuples types are defined in Slang with the `Tuple<...>` syntax, and +constructed with either a constructor or the `makeTuple` function: +```csharp +Tuple t0 = Tuple(5, 2.0f, false); +Tuple t1 = makeTuple(3, 1.0f, true); +``` + +Tuple elements can be accessed with `_0`, `_1` member names: +```csharp +int i = t0._0; // 5 +bool b = t1._2; // true +``` + +You can use the swizzle syntax similar to vectors and matrices to form new +tuples: + +```csharp +t0._0_0_1 // evaluates to (5, 5, 2.0f) +``` + +You can concatenate two tuples: + +```csharp +concat(t0, t1) // evaluates to (5, 2.0f, false, 3, 1.0f, true) +``` + +If all element types of a tuple conforms to `IComparable`, then the tuple itself +will conform to `IComparable`, and you can use comparison operators on the tuples +to compare them: + +```csharp +let cmp = t0 < t1; // false +``` + +You can use `countof()` on a tuple type or a tuple value to obtain the number of +elements in a tuple. This is considered a compile-time constant. +```csharp +int n = countof(Tuple); // 2 +int n1 = countof(makeTuple(1,2,3)); // 3 +``` + +All tuple types will be translated to `struct` types, and receive the same layout +as `struct` types. + ## `Optional` type Slang supports the `Optional` type to represent a value that may not exist. diff --git a/docs/user-guide/toc.html b/docs/user-guide/toc.html index ca6aac92a..5b48c0d9d 100644 --- a/docs/user-guide/toc.html +++ b/docs/user-guide/toc.html @@ -38,6 +38,7 @@
  • Initializers
  • Operator Overloading
  • Subscript Operator
  • +
  • Tuple Types
  • `Optional<T>` type
  • `if_let` syntax
  • `reinterpret<T>` operation
  • -- cgit v1.2.3