<feed xmlns='http://www.w3.org/2005/Atom'>
<title>slang.git/source/slang/bytecode.cpp, 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>2018-12-10T20:42:15+00:00</updated>
<entry>
<title>Remove the "VM" and "bytecode" features (#745)</title>
<updated>2018-12-10T20:42:15+00:00</updated>
<author>
<name>Tim Foley</name>
<email>tfoleyNV@users.noreply.github.com</email>
</author>
<published>2018-12-10T20:42:15+00:00</published>
<link rel='alternate' type='text/html' href='https://git.yummers.dev/slang.git/commit/?id=b2997170df7cc2703de714a946a38dc35058e7f8'/>
<id>urn:sha1:b2997170df7cc2703de714a946a38dc35058e7f8</id>
<content type='text'>
* Remove the "VM" and "bytecode" features

The "bytecode" in `bc.{h,cpp}` was an initial attempt at a serialized encoding for the Slang IR, but we now have the `ir-serialize.{h,cpp}` approach which was has been kept up to date much better.

Similarly, the "VM" in `vm.{h,cpp}` was intended to be a system for interpreting Slang code in the bytecode format directly (so that you could load and evaluate code in a Slang module in a lightweight fashion). This never got used past a single test, which we eventually disabled.

There are good ideas in some of this code, but at this point the implementations have bit-rotted to a point where trying to maintain it is more costly than it would be to re-created it if/when we ever decide these features are important again.

* fixup: remove slang-eval-test from Makefile
</content>
</entry>
<entry>
<title>Add a warning on missing return, and initial SCCP pass (#671)</title>
<updated>2018-10-12T19:23:14+00:00</updated>
<author>
<name>Tim Foley</name>
<email>tfoleyNV@users.noreply.github.com</email>
</author>
<published>2018-10-12T19:23:14+00:00</published>
<link rel='alternate' type='text/html' href='https://git.yummers.dev/slang.git/commit/?id=c9ad36868961009fcd67e579f9b51e1333688208'/>
<id>urn:sha1:c9ad36868961009fcd67e579f9b51e1333688208</id>
<content type='text'>
* Add a warning on missing return, and initial SCCP pass

The user-visible feature added here is a diagnostic for functions with non-`void` return type where control flow might fall off the end. This *sounds* like a trivial diagnostic to add as part of the front-end AST checking, but that can run afoul of really basic stuff like:

```hlsl
int thisFunctionisOkay(int a)
{
    while(true)
    {
        if(a &gt; 10) return a;
        a = a*2 + 1;
    }
    // no return here!
}
```

This function "obviously" doesn't need to have a `return` statement at the end there, but realizing this fact relies on the compiler to understand that the `while(true)` loop can't exit normally, and doesn't contain any `break` statement. One can write "obvious" examples that need more and more complex analysis to rule out.

The answer Slang uses for stuff like this is to do the analysis at the IR level right after initial code generation (this would be before serialization, BTW, so that attached `IRHighLevelDeclDecoration`s can be used).

When lowering the AST to the IR, we always emit a `missingReturn` instruction (a subtype of `IRUnreachable`) at the end of its body if it isn't already terminated. The IR analysis pass to detect missing `return` statements is then as simple as just walking through all the functions in the module and making sure they don't contain `missingReturn` instructions.

For that simple pass to work, we first need to make some effort to remove dead blocks that control flow can never reach. This change adds a very basic initial implementation of Spare Conditional Constant Propagation (SCCP), which is a well-known SSA optimization that combines constant propagation over SSA form with dead code elimination over a CFG to achieve optimizations that are not possible with either optimization along.

For the moment, we don't actually implement any constant *folding* as part of the SCCP pass, so we can eliminate the dead block in a case like the function above (and those in the test case added in this change), but will not catch things like a `while(0 &lt; 1)` loop. Handling more "obvious" cases like that is left for future work.

* fixup: warning on unreachable code

* Handle case where user of an inst isn't in same function/code

The code as assuming any instruction in the SSA work list has to come from the function/code being processed, but this misses the case where an instruction in a generic has a use inside the function that the generic produces.

This change adds code to guard against that case.
</content>
</entry>
<entry>
<title>Support for IRStringLit (#645)</title>
<updated>2018-09-19T19:27:50+00:00</updated>
<author>
<name>jsmall-nvidia</name>
<email>jsmall@nvidia.com</email>
</author>
<published>2018-09-19T19:27:50+00:00</published>
<link rel='alternate' type='text/html' href='https://git.yummers.dev/slang.git/commit/?id=653fe976af88fcf86162ca5bb1b46d4378864572'/>
<id>urn:sha1:653fe976af88fcf86162ca5bb1b46d4378864572</id>
<content type='text'>
* * Added support for strings in IR with IRStringLit - with storage of chars after it
* Added kIRDecorationOp_Transitory - can be used for detecting instructions constructed on stack
* Made IRConstant hashing work off type

* Fix comment that is out of date about how an instruction is determines to hold a transitory string.
</content>
</entry>
<entry>
<title>Introduce an IR-level type system (#481)</title>
<updated>2018-04-11T23:18:29+00:00</updated>
<author>
<name>Tim Foley</name>
<email>tfoleyNV@users.noreply.github.com</email>
</author>
<published>2018-04-11T23:18:29+00:00</published>
<link rel='alternate' type='text/html' href='https://git.yummers.dev/slang.git/commit/?id=baf194e7456ba4568dcf11249896af35b3ce18cc'/>
<id>urn:sha1:baf194e7456ba4568dcf11249896af35b3ce18cc</id>
<content type='text'>
* Introduce an IR-level type system

Up to this point, the Slang IR has used the front-end type system to represent types in the IR.
As a result (but ultimately more importantly) the IR representation of generics and specialization has used AST-level concepts embedded in the IR.
For example, to express the specialization of `vector&lt;T,N&gt;` to a concrete type `float` for `T`, we needed an IR operation that could represent the specialization, with operands that somehow represented the type argument `float`.
The whole thing was very complicated.

The big idea of this change is to introduce a new representation in which types in the IR are just ordinary instructions, so that using them as operands makes sense. The hierarchy of IR types closely mirrors the AST-side hierarchy for now, and that will probably be something we should maintain going forward.

In order to make these changes work, though, I also had to do major overhauls of things like the way substitutions are performed, how we check interface conformances, the way lookup through interface types is done, etc. etc. This is a big change, and unfortunately any attempt to summarize it in the commit message wouldn't do it justice.

* Fix 64-bit build warning

* Fix up some clang warnings/errors
</content>
</entry>
<entry>
<title>IR: "everything is an instruction" (#432)</title>
<updated>2018-03-01T21:11:24+00:00</updated>
<author>
<name>Tim Foley</name>
<email>tfoleyNV@users.noreply.github.com</email>
</author>
<published>2018-03-01T21:11:24+00:00</published>
<link rel='alternate' type='text/html' href='https://git.yummers.dev/slang.git/commit/?id=41dc26b9ef501e23563bdb0705ceecb15fd6c18d'/>
<id>urn:sha1:41dc26b9ef501e23563bdb0705ceecb15fd6c18d</id>
<content type='text'>
* IR: "everything is an instruction"

This change tries to streamline the representation of the IR in the following ways:

* Every IR value is an instruction (there is no `IRValue` type any more)

* All IR values that can contain other values share a single base (`IRParentInstruction`)

* Dynamic casts to specific IR instruction types can be accomplished with a new `as&lt;Type&gt;(inst)` operation, that uses the IR opcode to implement casts.

The biggest change in terms of number of lines is getting rid of `IRValue`. The diff here could probably be smaller if I'd just done `typedef IRInst IRValue;`.

Along the way I also renamed the `getArg`/`getArgs`/`getArgCount` combination over to `getOperand`/`getOperands`/`getOperandCount` to avoid being confusing when we have something like a `call` instruction where the "arguments" of the call don't line up with the operands of the instruction.

I also tried to clean up the representation of lists of child instructions to try to make it easier to iterate over them with C++ range-based `for` loops. Developers still need to be careful about mutating the contents of a block while iterating over it in this fashion (e.g. if you remove the "current" element, the iteration will end prematurely).

Probably the thorniest change here is that parameters are now just represented as the first N instructions in a block, which means:

* We need to perform a linear search to find the end of the parameter list. This is probably not often a problem, because usually you would be iterating over the parameters anyway, and that will be linear in the number of parameters.

* Algorithms that iterate over a block either need to ignore parameters, treat parameters just like other instructions, or somehow cleave the list into the range of parameters, and the range of "ordinary" instructions (which involves the same linear search above).

* When inserting into a block, we need to be careful not to insert instructions at invalid locations (e.g., insert a temporary before the parameters, or insert a parameter in the middle of the code). I can't pretend that I've handled the details of that here. (This is no different than having to make the same adjustments for phi nodes in a typical SSA representation)

  * One possible future-proof approach is to implement a pass that sorts the instructions in a block so that parameters always come first. That would let us implement passes without caring about this detail, and then clean up right before any pass that cares about the relative order of parameters and other instructions.

The current change is missing any work to make literals and other instructions that used to be `IRValue`s properly nest inside of their parent module. Right now these instructions are just left unparented, and may actually end up being shared between distinct modules. Fixing that will need a follow-up change. The biggest challenge there is that it introduces instructions at the global scope that aren't `IRGlobalValue`s.

This change doesn't try to take advantage of any of the new flexibility (e.g., by nesting `specialize` instructions inside of witness tables). The goal is to do exactly what we were doing before, just with a different  representation.

* Warning fix
</content>
</entry>
<entry>
<title>Initial work on validating "constexpr"-ness in IR (#420)</title>
<updated>2018-02-22T19:44:57+00:00</updated>
<author>
<name>Tim Foley</name>
<email>tfoleyNV@users.noreply.github.com</email>
</author>
<published>2018-02-22T19:44:57+00:00</published>
<link rel='alternate' type='text/html' href='https://git.yummers.dev/slang.git/commit/?id=7eaaf1aa1fdac3fd7ff7b64800a965a2b2c17f66'/>
<id>urn:sha1:7eaaf1aa1fdac3fd7ff7b64800a965a2b2c17f66</id>
<content type='text'>
* Initial work on validating "constexpr"-ness in IR

The underlying issue here is that certain operations in the target shading languages constrain their operands to be compile-time constants. A notable example is the optional texel offset parameter to the `Texture2D.Sample` operation.

When calling these operations in GLSL, the user is required to pass a "constant expression," and any variables in that expression must therefore be marked with the `const` qualifier (and themselves be initialized with constant expressions). Any GLSL output we generate must of course respect these rules.

When calling these operations in HLSL, the user is not so constrained. Instead, they can pass an arbitrary expression, which may involve ordinary variables with no particular markup, and then the compiler is responsible for determining if the actual value after simplification works out to be a constant. In some cases, the requirement that a value be constant might actually trigger things like loop unrolling. Also, it is okay to use a function parameter to determine such a constant expression, as long as the argument turns out to be a constant at all call sites.

The way we have decided to tackle these challenges in Slang is that we we propagate a notion of `constexpr`-ness through the IR. This is currently being tackled in `ir-constexpr.cpp` with a combination of forward and backward iterative dataflow:

* When the operands to an instruction are all `constexpr`, and the opcode is one we believe can be constant-folded, then we infer that the instruction *can* be evaluated as `constexpr`

* When instruction is required to be `constexpr`, then we infer that all of its operands are also required to be `constexpr`.

If this process ever infers that a function parameter is required to be `constexpr`, then we might have to continue propagation at all the call sites to that function.

If after all the propagation is done, there are any cases where an instruction is *required* to be `constexpr`, but it *can't* be `constexpr` (we weren't able to infer `constexpr`-ness for its operands), then we issue an error.

This implementation encodes the idea of `constexpr`-ness in the IR as part of the type system, using a simplified notion of rates. This change adds a `RateQualifiedType` that can represent `@R T`, and then introduces a `ConstExprRate` that can be used for `R`. Many accessors for the type information on IR nodes were updated to distinguish when one wants the "full" type of an IR value (which might include rate information) vs. just the "data" type.

A `constexpr` qualifier was added in the front-end, and is being used to decorate the texel offset parameter for `Texture2D.Sample`. Lowering from AST to IR looks for this qalifier and infers when a function parameter must be typed as `@ConstExpr T` instead of just `T`.

There are lots of limitations and gotchas in the implementation so far:

* The `@ConstExpr` rate is the only one added in this change, but it seems clear that the conceptual `ThreadGroup` rate that was added to represent `groupshared` should probably get folded into the representation.

* I'm not 100% pleased with how many places in the IR I have to special-case for rate-qualified types. At the same type, pulling out rate as a distinct field on `IRValue` would probably require that we pay attention to rate everywhere.

* I've added a test case to show that we can issue errors when users fail to provide a constant expression for the texel offset, but the actual error message isn't great because it doesn't indicate *why* a constant expression was required. Realistically the "initial IR" should contain a few more decorations we can use to relate error conditions back to the original code (even if this is in a side-band structure).

* I've added a test case that is supposed to show that we can back-propagate `constexpr`-ness to local variables, and I've manually confirmed that it works for Vulkan/SPIR-V output, but the level of Vulkan support in `render_test` today means I can't enable the test for check-in.

* While I'm attempting to propagate `@ConstExpr` information from callees to callers, I haven't implemented any logic to specialize callee functions based on values at call sites.

* In a similar vein, there is no handling of control-flow dependence in the current code. If we infer that a phi (block parameter) needs to be `@ConstExpr`, then it isn't actually enough to require that the inputs to the phi (arguments from predecessor blocks) are all `@ConstExpr` because we also need any control-flow decisions that pick which incoming edge we take to be `@ConstExpr` as well.

* As a practical matter, implicit propagation of `@ConstExpr` from a function body to a function parameter should only be allowed for functions that are "local" to a module. Any function that might be accessed from outside of a module should really have had its `@ConstExpr` parameter marked manually, and our pass should validate that they follow their own rules. Right now we have no kind of visibility (`public` vs `private`) system, so I'm kind of ignoring this issue.

While that is a lot of gaps, this is also just enough code to get the Falcor MultiPassPostProcess example working, so I'm inclined to get it checked in.

* Fixup: missing expected output for test

* Fixup: disable test that relies on [unroll] for now
</content>
</entry>
<entry>
<title>Basic IR support for `static const` globals (#404)</title>
<updated>2018-02-08T22:46:12+00:00</updated>
<author>
<name>Tim Foley</name>
<email>tfoleyNV@users.noreply.github.com</email>
</author>
<published>2018-02-08T22:46:12+00:00</published>
<link rel='alternate' type='text/html' href='https://git.yummers.dev/slang.git/commit/?id=c7c97ad4bb62b83efd6e26cdd4f38ebf164ec40e'/>
<id>urn:sha1:c7c97ad4bb62b83efd6e26cdd4f38ebf164ec40e</id>
<content type='text'>
* Basic IR support for `static const` globals

Our strategy for lowering global *variables* can fall back to putting their initialization into a function, but that isn't really appropriate for global constants (it also isn't appropriate for arrays, but we'll need to deal with that seaprately).

This change adds a distinct case for global constants (rather than treating them as variables), and forces the emission logic to always emit them as a single expression.
Doing this makes assumptions about how the IR for these constants gets emitted (and what optimziations might do to it).
In order to make things work, I had to switch the handling of initializer-list expressions to not be lowered via temporaries and mutation (since that isn't a good fit for reverting to a single expression).

I've added a single test case to ensure that this works in the simplest scenario. My next priority will be to see if this unblocks my work in Falcor.

* Fixup: bug fixes
</content>
</entry>
<entry>
<title>Parameter blocks (#245)</title>
<updated>2017-11-06T18:37:27+00:00</updated>
<author>
<name>Tim Foley</name>
<email>tfoleyNV@users.noreply.github.com</email>
</author>
<published>2017-11-06T18:37:27+00:00</published>
<link rel='alternate' type='text/html' href='https://git.yummers.dev/slang.git/commit/?id=9919c823938ae929b16efac9d507f6d5eb122bf4'/>
<id>urn:sha1:9919c823938ae929b16efac9d507f6d5eb122bf4</id>
<content type='text'>
* Rename existing ParameterBlock to ParameterGroup

We are planning to add a new `ParameterBlock&lt;T&gt;` type, which maps to the notion of a "parameter block" as used in the Spire research work.
Unfortunately, the compiler codebase already uses the term `ParameterBlock` as catch-all to encompass all of HLSL `cbuffer`/`tbuffer` and GLSL `uniform`/`buffer`/`in`/`out` blocks (all of which are lexical `{}`-enclosed blocks that define parameters...).

This change instead renames all of the existing concepts over to `ParameterGroup`, which isn't an ideal name, but at least doesn't directly overlap the new terminology or any existing terminology.

The new `ParameterBlockType` case will probably be a subclass of `ParameterGroupType`, since it is a logical extension of the underlying concept.

* Add Shader Model 5.1 profiles

The HLSL `register(..., space0)` syntax is only allowed on "SM5.1" and later profiles (which is supported by the newer version of `d3dcompiler_47.dll` that comes with the Win10 SDK, but not the older version of `d3dcompiler_47.dll` - good luck figuring out which you have!).

This change adds those profiles to our master list of profiles, and nothing else.

* First pass at support for `ParameterBlock&lt;T&gt;`

- Add the type declaration in stdlib

- Add a special case of `ParameterGroupType` for parameter blocks

- Handle parameter blocks in type layout (currently handling them identically to constant buffers for now, which isn't going to be right in the long term)

- Add an IR pass that basically replaces `ParameterBlock&lt;T&gt;` with `T`
  - Eventually this should replace it with either `T` or `ConstantBuffer&lt;T&gt;`, depending on whether the layout that was computed required a constant buffer to hold any "free" uniforms

- Add first stab at an IR pass to "scalarize" global variables using aggregate types with resources inside.
  - This currently only applies to global variables, so it won't handle things passed through functions, or used as local variables
  - It also only supports cases where the references to the original variable are always references to its fields, and not the whole value itself

- Add a single test case that technically passes with this level of support, but probably isn't very representative of what we need from the feature

* Fold parameter-block desugaring into a more complete "type legalization" pass

The basic problem that was arising is that once you desugar `ParameterBlock&lt;T&gt;` into `T`, you then need todeal with splitting `T` into its constituent fields if it contains any resource types.
Handling those transformations by following the usual use-def chains wasn't really helping, because you might need systematic rewriting that can really only be handled bottom-up.

This change adds a new pass that is intended to perform multiple kinds of type "legalization" at once:

- It will turn `ParameterBlock&lt;T&gt;` into `T`
  - It may at some point also convert `ConstantBuffer&lt;T&gt;` into `T` as well
- It will turn an value of an aggregate type that contains resources into N different values (one per field)
  - As a result of this, it will also deal with AOS-to-SOA conversion of these types

Legalization is applied to *every* function/instruction/value, so that it can make large-scale changes that would be tough to manage with a work list.

This pass needs to be run *after* generics have been fully specialized, so that we know we are always dealing with fully concrete types, so that their legalization for a given target is completely known.

This is still work in progress; there's more to be done to get this working with all our test cases, and finish the remaining `ParameterBlock&lt;T&gt;` work.

* Improve binding/layout information when using parameter blocks

- When doing type layout for a parameter block, don't include the resources consumed by the element type in the resource usage for the parameter block
  - Note that this is pretty much identical to how a `ConstantBuffer&lt;T&gt;` does not report any `LayoutResourceKind::Uniform` usage, except that `ParameterBlock&lt;T&gt;` is *also* going to hide underlying texture/sampler reigster usage
  - The one exception here is that any nested items that use up entire `space`s or `set`s those need to be exposed in the resource usage of the parent (I don't have a test for this)

- When type legalization needs to scalarize things, it must propagate layout information down to the new leaf variables. In general, the register/index for a new leaf parameter should be the sum of the offsets for all of the parent variables along the "chain" from the original variable down to the leaf (we aren't dealing with arrays here just yet).

- When type legalization decides to eliminate a pointer(-like) type (e.g., desugar `ParameterBlock&lt;T&gt;` over to `T`), actually deal with that in terms of the `LegalVal`s created, so that we can know to turn a `load` into a no-op when applied to a value that got indirection removed.

- Hack up the "complex" parameter-block test so that it actually passes (the big hack here is that the HLSL baseline is using names that are generated by the IR, and are unlikely to be stable as we add/remove transformations).
  - Note: I can't make these be compute tests right now, because regsiter spaces/sets are a feature of D3D12/Vulkan, and our test runner isn't using those APIs.
</content>
</entry>
<entry>
<title>fixes x64 warnings</title>
<updated>2017-11-04T22:43:03+00:00</updated>
<author>
<name>Yong He</name>
<email>yonghe@outlook.com</email>
</author>
<published>2017-11-04T22:43:03+00:00</published>
<link rel='alternate' type='text/html' href='https://git.yummers.dev/slang.git/commit/?id=215ce206838db63fdd310a0ababe421799011d21'/>
<id>urn:sha1:215ce206838db63fdd310a0ababe421799011d21</id>
<content type='text'>
</content>
</entry>
<entry>
<title>fix linux build</title>
<updated>2017-11-04T20:23:21+00:00</updated>
<author>
<name>Yong He</name>
<email>yonghe@outlook.com</email>
</author>
<published>2017-11-04T20:23:21+00:00</published>
<link rel='alternate' type='text/html' href='https://git.yummers.dev/slang.git/commit/?id=a7dd782d7895e1f277573fb9923be653ab813941'/>
<id>urn:sha1:a7dd782d7895e1f277573fb9923be653ab813941</id>
<content type='text'>
</content>
</entry>
</feed>
