<feed xmlns='http://www.w3.org/2005/Atom'>
<title>slang.git/source/slang/ir.h, branch master</title>
<subtitle>Making it easier to work with shaders</subtitle>
<id>https://git.yummers.dev/slang.git/atom?h=master</id>
<link rel='self' href='https://git.yummers.dev/slang.git/atom?h=master'/>
<link rel='alternate' type='text/html' href='https://git.yummers.dev/slang.git/'/>
<updated>2019-05-31T21:20:37+00:00</updated>
<entry>
<title>Use slang- prefix on slang compiler and core source (#973)</title>
<updated>2019-05-31T21:20:37+00:00</updated>
<author>
<name>jsmall-nvidia</name>
<email>jsmall@nvidia.com</email>
</author>
<published>2019-05-31T21:20:37+00:00</published>
<link rel='alternate' type='text/html' href='https://git.yummers.dev/slang.git/commit/?id=6cbc3929a54d37bd23cb5efa8e3320ba02f78b2f'/>
<id>urn:sha1:6cbc3929a54d37bd23cb5efa8e3320ba02f78b2f</id>
<content type='text'>
* Prefixing source files in source/slang with slang-

* Prefix source in source/slang with slang- prefix.

* Rename core source files with slang- prefix.

* Update project files.

* Fix problems from automatic merge.
</content>
</entry>
<entry>
<title>Hotfix/improve glsl semantic conversion review (#968)</title>
<updated>2019-05-22T16:00:20+00:00</updated>
<author>
<name>jsmall-nvidia</name>
<email>jsmall@nvidia.com</email>
</author>
<published>2019-05-22T16:00:21+00:00</published>
<link rel='alternate' type='text/html' href='https://git.yummers.dev/slang.git/commit/?id=3247174cdb00836435794e3f07daad70bc92b66f'/>
<id>urn:sha1:3247174cdb00836435794e3f07daad70bc92b66f</id>
<content type='text'>
* Small changes based on review

* Remove the explicit 'nominal' tests
* Made isValueEqual and isEqual on on IRConstant take a pointer
* Small improvements to comments, and clarity of using 'nominal'

* Simplify comparison by just using isTypeOperandEqual as basis for isTypeEqual

* Use cross compile to test half-texture.slang on glsl

* Don't need half-texture.slang.expected

* Fix handling of nominal comparison based on review, ensuring that for nominal insts, they can only be compared by pointer.
</content>
</entry>
<entry>
<title>Hotfix/improve glsl semantic conversion (#965)</title>
<updated>2019-05-21T18:44:09+00:00</updated>
<author>
<name>jsmall-nvidia</name>
<email>jsmall@nvidia.com</email>
</author>
<published>2019-05-21T18:44:09+00:00</published>
<link rel='alternate' type='text/html' href='https://git.yummers.dev/slang.git/commit/?id=c2b4c5838431e12abb6f233c459d3d6a717aad18'/>
<id>urn:sha1:c2b4c5838431e12abb6f233c459d3d6a717aad18</id>
<content type='text'>
* Specify glsl semantic format - such that conversions are possible from hlsl sematics.

* Comment improvements. Give appropriate type in glsl for sv_tessfactor. Note that sv_tessfactor is not functional though.

* Work in progress for comparison of types.

* * Fix type comparison issues around the hash.
* Fix tests whos output changed with use of isTypeEqual
</content>
</entry>
<entry>
<title>Allow interface types to be used inside of structs (#966)</title>
<updated>2019-05-21T15:52:37+00:00</updated>
<author>
<name>Tim Foley</name>
<email>tfoleyNV@users.noreply.github.com</email>
</author>
<published>2019-05-21T15:52:37+00:00</published>
<link rel='alternate' type='text/html' href='https://git.yummers.dev/slang.git/commit/?id=7ffe6f03976c98ba0233483d0182fc0ad600fd7a'/>
<id>urn:sha1:7ffe6f03976c98ba0233483d0182fc0ad600fd7a</id>
<content type='text'>
Previously, interface types were allowed to be used directly as function parameters, local variables, and global shader parameters.
Using an interface type as a field of a `struct` type or a `cbuffer` declaration was not implemented.
This change adds that support, and fixes several unrelated issues that caused problems in doing so.

* The most important work here was adding a case for `IRStructType` to `maybeSpecializeBindExistentialsType` that creates a specialized variant of a `struct` type on-demand based on specialization operands. This logic loops over the fields of the original struct, and creates new fields by binding the existentials/interfaces in the type of each field. Caching is used to ensure that the same `struct` type specialized to the same operands should yield the same result.

* To allow subsequent specialization to occur when a `struct` with interface-type fields is used, it was also necessary to specialize field-address and field-extract instructions in cases where the value that the field is being extracted from is a `wrapExistential`.

* Similarly, we neede to make sure that the logic for specializing called functions based on the concrete types for interfaces in the argument list would also take into account `struct` types with existential-type fields inside of them.

* Doing the above changes revealed some serious flaws in how the `ir-specialize.cpp` logic was tracking which instructions still needed to be processed. It had previously been assuming that it could assume any relevant instructions were on its work list, and when the work list went empty it could exit. This runs into two problems: (1) sometimes we create new instructions when specializing, and it may be impossible to ensure that all the new instructions (e.g., those created by utility routines in other files) get added to the work list, and (2) sometimes the instruction(s) that need to be re-visited when we specialize something aren't its direct users, but instead somethign that transitively depends on the instruction.

  These issues were fixed by two changes to the pass: (1) we now maintain a list of known "clean" instructions instead of implicitly using the work-list as a list of "dirty" instructions (so that implicitly any new instruction is dirty), and periodically iterating over all instructions to add the non-clean ones to the work list for processing, and (2) when an instruction is specialized/replaced we mark everything that transitively depends on it "dirty" (by removing it from the "clean" list).

* Added some logic to "fix up" the type of an IR function after changes that might modify its parameter list. Failing to have this logic meant that certain types were still live (because they were referenced by a function type) that couldn't actually be emitted as legal HLSL/GLSL.

* Added some special cases to IR instruction creation for `wrapExistential` and `BindExistentialsType` so that they act as no-ops when there are no "slots" providing specialization information. This helps avoid some special cases when specializing structure fields (since some fields specialization and others don't, so in general there are zero or more operands specific to each field).

* Added a test case that uses an interface type in a `cbuffer`, as well as an interface type in a `struct` passed as an entry-point `uniform` parameter.

* Fixed up some parts of the `.natvis` files to reflect naming changes from a previous PR and thus restore some of the useful Visual Studio debugging experience for Slang.</content>
</entry>
<entry>
<title>Fix handling of arrays of resources in type legalization (#896)</title>
<updated>2019-03-12T17:45:39+00:00</updated>
<author>
<name>Tim Foley</name>
<email>tfoleyNV@users.noreply.github.com</email>
</author>
<published>2019-03-12T17:45:39+00:00</published>
<link rel='alternate' type='text/html' href='https://git.yummers.dev/slang.git/commit/?id=9722990745f4e91ab1bf9fb682c72e173cd123b4'/>
<id>urn:sha1:9722990745f4e91ab1bf9fb682c72e173cd123b4</id>
<content type='text'>
Before type legalization we might have code like: (using pseudo-Slang-IR):

    struct P { ... Texture2D&lt;float&gt;[] t; }
    global_param p : ParameterBlock&lt;P&gt;;
    ...

    // p.t[someIndex].Load(...);
    //
    let ptrToArrayOfTextures = getFieldPtr(p, "t")                            : Ptr&lt;Texture2D&lt;float&gt;[]&gt;;
    let ptrToTexture         = getElementPtr(ptrToArrayOfTextures, someIndex) : Ptr&lt;Texture2D&lt;float&gt;&gt;;
    let texture              = load(ptrToTexture)                             : Texture2D&lt;float&gt;;
    let result               = call(loadFunc, texture, ...)                   : float;

Legalization needs to move the `t` array there out of the `p` parameter block, so the global declarations become something like:

    struct P_Ordinary { ... }; // no more "t" field
    global_param p_ordinary : ParameterBlock&lt;p_ordinary);
    global_param p_t : Texture2D&lt;float&gt;[];

In terms of the code to access `p.t[someIndex]` the problem is that `p_t` has one less level of indirection than `p.t` had. We solve this in the type legalization pass using "pseudo-types" and "pseudo-values," where one of the cases is `implicitIndirect` which holds a value of type `T`, but indicates that it should act like a value of type `T*`.

We then use some basic rules for dealing with `implicitIndirect` values, such as:

    load(implicitDeref(x)) : T =&gt; x : T
    getFieldPtr(implicitDeref(s), f) =&gt; implicitDeref(getField(s, f))
    getElementPtr(implicitDeref(a), i) =&gt; implicitDeref(getElement(a, i))

The bug here was that for the `getFieldPtr` and `getElementPtr` cases, we weren't computing the type of the `getField` or `getElement` instruction correctly. We were copying the type from the `getFieldPtr` or `getElementPtr` operation over directly, but those will be *pointer* types and we need the type of whatever they point to.

Once the types are fixed, we can properly generate legalized IR for `p.t[someIndex].Load(...) that looks like:

    let arrayOfTextures = p_t                                    : Texture2D&lt;float&gt;[];
    let texture         = getElement(arrayOfTextures, someIndex) : Texture2D&lt;float&gt;;
    let result           = call(loadFunc, texture, ...)          : float;

The old was giving the `texture` intermediate a type of `Ptr&lt;Texure2D&lt;float&gt;&gt;`. That didn't actually trip up too many things, because we mostly just went on to emit code from something with slightly incorrect types for intermediates that never show up in the generated HLSL/GLSL.

Where this caused a problem is for some of the intrinsic function definitions for the GLSL/Vulkan back-end, because those do things that inspect operand types. In particular the `$z` opcode in our intrinsic function strings triggers logic that looks at a texture operand, and uses its type to try to find the appropriate swizzle to get from a 4-component vector to the appropriate type for the operation (e.g., for a load from a `Texture2D&lt;float&gt;` we need to swizzle with `.x` to get a single scalar out of the matching GLSL texture fetch operation).

The main fix in this change is thus to make `getElementPtr` and `getFieldPtr` legalization properly account for the fact that when switching to `getElement` or `getField` we need a result type that is the "pointee" of the original result.

There was already logic to extract the pointed-to type from a pointer in `ir-specialize.cpp`, so I extracted that to a re-usable function in the IR as `tryGetPointedToType` (returns null if the type isn't actually a pointer).
This logic needed to be extended for type legalization, to deal with the various "pseudo-type" cases.

There is another fix in this change which is marking the `NonUniformResourceIndex` function as `[__readNone]`, which enables it to be more aggressively folded into use sites. Without that fix, we risk emitting code like:

```glsl
int tmp = nonUniformEXT(someIndex);
vec4 result = texelFetch(arrayOfTextures[tmp], ...);
```

The problem with that code is that (at least by my reading of the spec), assigning to the variable `tmp` that isn't declared with the `nonUniformEXT` qualifier effectively loses that qualifier, and drivers are free to assume that `tmp` is uniform when used to index into `arrayOfTextures`.

Marking the `NonUniformResourceIndex` function as `[__readNone]` indicates that it has no side effects, which should mean that our emit logic no longer needs to emit it was its own line of code to be safe.
The effects of this change are confirmed by both the new test case added, and the existing `non-uniform-indexing` test.</content>
</entry>
<entry>
<title>Improve support for interfaces as shader parameters (#886)</title>
<updated>2019-03-09T00:24:02+00:00</updated>
<author>
<name>Tim Foley</name>
<email>tfoleyNV@users.noreply.github.com</email>
</author>
<published>2019-03-09T00:24:02+00:00</published>
<link rel='alternate' type='text/html' href='https://git.yummers.dev/slang.git/commit/?id=4f94dd46a2d885e570814dd14a5e46f8e0814802'/>
<id>urn:sha1:4f94dd46a2d885e570814dd14a5e46f8e0814802</id>
<content type='text'>
* Improve support for interfaces as shader parameters

This change adds two main things over the existing support:

1. It is now possible to plug in concrete types that actually contain (uniform/ordinary) fields for the existential type parameters introduced by interface-type shader parameters. The `interface-shader-param2.slang` test shows that this works.

2. There is a limited amount of support for doing correct layout computation and generating output code that matches that layout, so that interface and ordinary-type fields can be interleaved to a limited extent. The `interface-shader-param3.slang` test confirms this behavior.

There are several moving pieces in the change.

* When it comes to terminology, we try to draw a more clear distinction between existial type parameters/arguments and existential/object value parametes/arguments. A simple way to look at it is that an `IFoo[3]` shader parameter introduces a single existential type parameter (so that a concrete type argument like `SomeThing` can be plugged in for the `IFoo`) but introduces three existential object/value parameters (to represent the concrete values for the array elements).

* At the IR level, we support a few new operations. A `BindExistentialsType` can take a type that is not itself an interface/existential type but which depends on interfaces/existentials (e.g., `ConstantBuffer&lt;IFoo&gt;`) and plug in the concrete types to be used for its existential type slots.

* Then a `wrapExistentials` instruction can take a type with all the existentials plugged in (possibly by `BindExistentialsType`) and wrap it into a value of the existential-using type (e.g., turn `ConstantBuffer&lt;SomeThing&gt;` into a `ConstantBuffer&lt;IFoo&gt;`).

* The IR passes for doing generic/existential specialization have been updated to be able to desugar uses of these new operations just enough so that a `ConstantBuffer&lt;IFoo&gt;` can be used.

* When we specialize an IR parameter of an interface type like `IFoo` based on a concrete type `SomeThing`, we turn the parameter into an `ExistentialBox&lt;SomeThing&gt;` to reflect the fact that we are conceptually referring to `SomeThing` indirectly (it shouldn't be factored into the layout of its surrounding type).

* Parameter binding was updated so that it passes along the bound existential type arguments in a `Program` or `EntryPoint` to type layout, so that we can take them into account. The type layout code needs to do a little work to pass the appropriate range of arguments along to sub-fields when computing layout for aggregate types.

* Type layout was updated to have a notion of "pending" items, which represent the concrete types of data that are logically being referenced by existential value slots. The basic idea is that these values aren't included in the layout of a type by default, but then they get "flushed" to come after all the non-existential-related data in a constant buffer, parameter block, etc.

* The logic for computing a parameter group (`ConstantBuffer` or `ParameterBlock`) layout was updated to always "flush" the pending items on the element type of the group, so that the resource usage of specialized existential slots would be taken into account.

* The type legalization pass has been adapted so that we can derive two different passes from it. One does resource-type legalization (which is all that the original pass did). The new pass uses the same basic machinery to legalize `ExistentialBox&lt;T&gt;` types by moving them out of their containing type(s), and then turning them into ordinary variables/parameters of type `T`.

Big things missing from this change include:

- Nothing is making sure that "pending" items at the global or entry-point level will get proper registers/bindings allocated to them. For the uniform case, all that matters in the current compiler is that we declare them in the right order in the output HLSL/GLSL, but for resources to be supported we will need to compute this layout information and start associating it with the existential/interface-type fields.

- Nothing is being done to support `BindExistentials&lt;S, ...&gt;` where `S` is a `struct` type that might have existential-type fields (or nested fields...). Eventually we need to desugar a type like this into a fresh `struct` type that has the same field keys as `S`, but with fields replaced by suitable `BindExistentials` as needed. (The hard part of this would seem to be computing which slots go to which fields). As a practial matter, this missing feature means that interface-type members of `cbuffer` declarations won't work.

The current tests carefully avoid both of these problems. They don't declare any buffer/texture fields in the concrete types, and they don't make use of `cbuffer` declarations or `ConstantBuffer`s over structure types with interface-type fields.

* fixup: add override to methods

* fixup: typos
</content>
</entry>
<entry>
<title>First steps toward supporting interface-type parameters on shaders (#852)</title>
<updated>2019-02-19T19:46:05+00:00</updated>
<author>
<name>Tim Foley</name>
<email>tfoleyNV@users.noreply.github.com</email>
</author>
<published>2019-02-19T19:46:05+00:00</published>
<link rel='alternate' type='text/html' href='https://git.yummers.dev/slang.git/commit/?id=32135c5bdfb4d387f8227742a2d2fd555898aca8'/>
<id>urn:sha1:32135c5bdfb4d387f8227742a2d2fd555898aca8</id>
<content type='text'>
* First steps toward supporting interface-type parameters on shaders

What's New
----------

From the perspective of a user, the main thing this change adds is the ability to declare top-level shader parameters (either at global scope, or in an entry-point parameter list) with interface types. For example, the following becomes possible:

```hlsl
// Define an interface to modify values
interface IModifier { float4 modify(float4 val); }

// Define some concrete implementations
struct Doubler : IModifier
{
    float4 modify(float4 val) { return val + val; }
}
struct Squarer : IModifier { ... }

// Define a global shader parameter of interface type
IModifier gGlobalModifier;

// Define an entry point with an interface-type `uniform` parameter
void myShader(
    unifrom IModifier entryPointModifier,
            float4    inColor  : COLOR,
        out float4    outColor : SV_Target)
{
    // Use the interface-type parameters to compute things
    float4 color = inColor;
    color = gGlobalModifier.modify(color);
    color = entryPointModifier.modify(color);
    outColor = color;
}
```

The user can specialize that shader by specifying the concrete types to use for global and entry-point parameters of interface types (e.g., plugging in `Doubler` for `gGlobalModifier` and `Squarer` for `entryPointModifier`).

The "plugging in" process is done in terms of a concept of both global and local "existential slots" which are a new `LayoutResourceKind` that represents the holes where concrete types need to be plugged in for existential/interface types.

In simple cases like the above, each interface-type parameter will yield a single existential slot in either the global or entry-point parameter layout. Users can query the start slot and number of slots for each shader parameter, just like they would for any other resource that a parameter can consume. Before generating specialized code, the user plugs in the name of the concrete type they would like to use for each slot using `spSetTypeNameForGlobalExistentialSlot` and/or `spSetTypeNameForEntryPointExistentialSlot`.

There are some major limitations to the implementation in this first change:

* Parameters must be of interface type (e.g., `IFoo`) and not an array (`IFoo[3]`), or buffer (`ConstantBuffer&lt;IFoo&gt;`) over an interface type. Similarly, `struct` types with interface-type fields still don't work.

* The work on interface-type function parameters still doesn't include support for `out` or `inout` parameters, nor for functions that return interface types (that isn't technically related to this change, but affects its usefullness).

* No work is being done to correctly lay out shader parameters once the concrete types for existential slots are known, so that this change really only works when the concrete type that gets plugged in is empty.

These limitations are severe enough that this feature isn't really usable as implemented in this change, and this merely represents a stepping stone toward a more complete implementation.

Implementation
--------------

The API side of thing largely mirrors what was already done to support passing strings for the type names to use for global/entry-point generic arguments, so there should be no major surprises there.

The logic in `check.cpp` computes the list of existential slots when creating unspecialized `Program`s and `EntryPoint`s (this is logically the "front end" of the compiler), and then checks the supplied argument types against what is expected in each slot when creating specialized `Program`s and `EntryPoint`s. This again mirrors how generic arguments are handled.

Type layout was extended to compute the number of existential slots that a type consumes, and will thus automatically assign ranges of slots to top-level and entry-point shader parameters in the same way it already allocates `register`s and `binding`s. The big missing feature is the ability to specialize a layout to account for the concrete types plugged into the existential-type slots.

IR generation for specialized programs and entry points was slightly extended so that it attaches information about the concrete types plugged into the existential slots, and the witness tables that show how they conform to the interface for that slot. The linking step needed some small tweaks to make sure that information gets copied over to the target-specific program when we start code generation.

The meat of the IR-level work is in `ir-bind-existentials.cpp`, which takes the information that was placed in the IR module by the generation/linking steps and uses it to rewrite shader parameters. For example, if there is a shader parameter `p` of type `IModifier`, and the corresponding existential slot has the type `Doubler` in it, we will rewrite the parameter to have type `Doubler`, and rewrite any uses of `p` to instead use `makeExistential(p, /*witness that Doubler conforms to IModifier*/)`.

Once the replacement is done on the parameters, the existing work for specializing existential-based code when the input type(s) are known kicks in and does the rest.

Testing
-------

A single compute test is added to validate that this feature works. It is narrowly tailored to not require any of the features not supported by the initial implementation (e.g., all of the concrete types used have no members).

The test case *does* include use of an associated type through one of these existential-type parameters, which has exposed a subtle bug in how "opening" of existential values is implemented in the front-end. Rather than fix the underlying problem, I cleaned up the code in the front-end to special case when the existential value being opened is a variable bound with `let`, to directly use a reference to that variable rather than introduce a temporary. Similarly, in the IR generation step, I added an optimization to make variables declared with `let` skip introducing an IR-level variable and just use the SSA value of their initializer directly instead.

* fixup: missing files

* fixup: incorrect type for unreachable return

* fixup: actually comment ir-bind-existentials.cpp
</content>
</entry>
<entry>
<title>Feature/as refactor (#817)</title>
<updated>2019-01-31T15:14:26+00:00</updated>
<author>
<name>jsmall-nvidia</name>
<email>jsmall@nvidia.com</email>
</author>
<published>2019-01-31T15:14:26+00:00</published>
<link rel='alternate' type='text/html' href='https://git.yummers.dev/slang.git/commit/?id=11c547d1e94fa620f527c3590174e6e25ab21883'/>
<id>urn:sha1:11c547d1e94fa620f527c3590174e6e25ab21883</id>
<content type='text'>
* Made dynamicCast a free function.

* Replace As with as or dynamicCast depending on if it is a type.

* Fix problem with using non smart pointer cast.

* Removed legacy asXXXX methods.

* Remove As from Type.

* Removed As from Qual type -&gt; made coercable into Type*, such that can just use free 'as'.

* Remove left over QualType::As() impl.

* Remove As from SyntaxNodeBase.

* Made as for instructions implemented by dynamicCast.

* Replace As on DeclRef. Use the global as&lt;&gt; to do the cast.

* Add const safe versions of dynamicCast and as for IRInst
</content>
</entry>
<entry>
<title>Support function parameters of existential (interface) type (#802)</title>
<updated>2019-01-28T22:20:44+00:00</updated>
<author>
<name>Tim Foley</name>
<email>tfoleyNV@users.noreply.github.com</email>
</author>
<published>2019-01-28T22:20:44+00:00</published>
<link rel='alternate' type='text/html' href='https://git.yummers.dev/slang.git/commit/?id=3c3513ab501277333d1062ad2737ac4a60dac6f7'/>
<id>urn:sha1:3c3513ab501277333d1062ad2737ac4a60dac6f7</id>
<content type='text'>
* Support function parameters of existential (interface) type

The basic idea here is that you can define a function that takes an interface-type parameter:

```hlsl
interface IThing { void doSOmething(); }
void coolFunction(IThing thing) { ... thing.doSomething() ... }
```

and call it with a concrete value that implements the given interface:

```hlsl
struct Stuff : IThing { void doSomething() { /* secret sauce */ } }
...
Stuff stuff;
coolFunction(stuff);
```

The compiler implementation will specialize `coolFunction` based on the concrete type that was actually passed in, resulting in output code along the lines of:

```hlsl
struct Stuff { ... }
void Stuff_doSomething(Stuff this) { /* secret sauce */ }

void coolFunction_Stuff(Stuff thing) { ... Stuff_doSomething(thing); }
```

In terms of implementation the new specialization approach has been integrated into the existing pass for generic specialization (which has been refactored significantly along the way), because generic specialization can open up opportunities for existential/interface simplification and vice versa, so there is no fixed interleaving of the two passes that can clean up everything.

The new logic therefore subsumes the old code for simplifying existential types (which only worked on local variables) in `ir-existential.{h,cpp}`. The local simplification rules from that implementation have become part of the core specialization pass instead, so that they can open up further transformation opportunities enabled by existential-type simplifications.

This code in place right now only handles the basic case of a function parameter that directly uses an interface type, and not one that wraps up an interface type in an array, structure, etc. Additional simplifications need to be introduced to deal with those cases as well.

* fixup: typos
</content>
</entry>
<entry>
<title>Initial support for dynamic dispatch using "tagged union" types (#772)</title>
<updated>2019-01-16T20:48:11+00:00</updated>
<author>
<name>Tim Foley</name>
<email>tfoleyNV@users.noreply.github.com</email>
</author>
<published>2019-01-16T20:48:11+00:00</published>
<link rel='alternate' type='text/html' href='https://git.yummers.dev/slang.git/commit/?id=aedf61784606406c090302efd8b7ac668ac997fc'/>
<id>urn:sha1:aedf61784606406c090302efd8b7ac668ac997fc</id>
<content type='text'>
* Initial support for dynamic dispatch using "tagged union" types

Suppose a user declares some generic shader code, like the following:

```hlsl
interface IFrobnicator { ... }
type_param T : IFrobincator;
ParameterBlock&lt;T : IFrobnicator&gt; gFrobnicator;
...
gFrobincator.frobnicate(value);
```

and then they have some concrete implementations of the required interface:

```hlsl
struct A : IFrobnicator { ... }
struct B : IFrobnicator { ... }
```

The current Slang compiler allows them to generate  distinct compiled kernels for the case of `T=A` and the case of `T=B`. This means that the decision of which implementation to use must be made at or before the time when a shader gets bound in the application.

This change adds a new ability where the Slang compiler can generate code to handle the case where `T` might be *either* `A` or `B`, and which case it is will be determined dynamically at runtime. This means a single compiled kernel can handle both cases, and the decision about which code path to run can be made any time before the shader executes.

This new option is supported by defining a *tagged union* type. Via the API, the user specifies that `T` should be specialized to `__TaggedUnion(A,B)` (the double underscore indicates that this is an experimental and unsupported feature at present). We refer to the types `A` and `B` here as the "case" types of the tagged union. Conceptually, the compiler synthesizes a type something like:

```hlsl
struct TU { union { A a; B b; } payload; uint tag; }
```

The user can then allocate a constant buffer to hold their tagged union type, and when they pick a concrete type to use (say `B`), they fill in the first `sizeof(B)` bytes of their buffer with data describing a `B` instance, and then set the `tag` field to the appopriate 0-based index of the case type they chose (in this case the `B` case gets the tag value `1`).

Actually implementing tagged unions takes a few main steps:

* Type parsing was extended to special-case `__TaggedUnion` as a contextual keyword. This is really only intended to be used when parsing types from the API or command-line, and Bad Things are likely to happen if a user ever puts it directly in their code. Eventually construction of tagged unions should be an API feature and not part of the language syntax.

* Semantic checking was extended to recognize that a tagged union like `__TaggedUnion(A,B)` shoud support an interface like `IFrobnicator` whenever all of the case types suport it, as long as the interface is "safe" for use with tagged unions (which means it doesn't use a few of the advancd langauge features like associated types).

* The IR was extended with instructions to represent tagged union types and to extract their tag and the payload for the different cases as needed.

* IR generation was extended to synthesize implementations of interface methods for any interface that a tagged union needs to support. Right now the implementation is simplistic and only handles simple method requirements, which it does by emitting a `switch` instruction to pick between the different cases.

* A new IR pass was introduced to "desugar" any tagged union types used in the code. The downstream HLSL and GLSL compilers don't support `union`s, so we have to instead emit a tagged union as a "bag of bits" and implement loading the data for particular cases from it manually.

* Final code emit mostly Just Works after the above steps, but we had to introduce an explicit IR instruction for bit-casting to handle the output of the desugaring pass.

There are a bunch of gaps and caveats in this implementation, but that seems reasonable for something that is an experimental feature. The various `TODO` comments and assertion failures in unimplemented cases are intended, so that this work can be checked in even if it isn't feature-complete.

* fixup: missing files

* fixup: typos
</content>
</entry>
</feed>
