https://github.com/shader-slang/slang
Revision fae3d9ae91a24e59ce6ec64b8a1217fa81f5acee authored by Tim Foley on 19 November 2019, 21:53:52 UTC, committed by GitHub on 19 November 2019, 21:53:52 UTC
* Initial work for "global generic value parameters"

The main new feature here is support for the `__generic_value_param` keyword, which introduces a *global generic value parameter*.
For example:

    __generic_value_param kOffset : uint = 0;

This declaration introduces a global generic value parameter `kOffset` of type `uint` that has a nominal default value of zero.

The broad strokes of how this feature was added are as follows:

* A new `GlobalGenericValueParamDecl` AST node type is introduces in `slang-decl-defs.h`

* A new `parseGlobalGenericValueParamDecl` subroutine is added to `slang-parser.cpp`, and is added to the list of declaration cases as the callback for the `__generic_value_param` name.

* Cases for `GlobalGenericValueParamDecl` are added to the declaration checking passes in `slang-check-decl.cpp`, mirroring what is done for other variable declaration cases.

* A case for `GlobalGenericValueParamDecl` is aded to the `Module::_collectShaderParams` function, so that it is recognized as a kind of specialization parameter. This introduces a specialization parameter of flavor `SpecializationParam::Flavor::GenericValue` (which was already defined before this change, although it was unused).

* A case for `SpecializationParam::Flavor::GenericValue` is added in `Module::_validateSpecializationArgsImpl` to check that a specialization argument represents a compile-time-constant value (not a type).

* A case for `GlobalGenericValueParmDecl` is introduced in `slang-lower-to-ir.cpp` that introduces a global generic parameter in the IR

* The `IRBuilder` is extended to support creating `IRGlobalGenericParam`s for the distinct cases of type, witness-table, and value parameters. The same IR instruction type/opcode is used for all cases, and only the type of the IR instruction differs.

* The existing mechanisms for lowering specialization arguments to the IR, and doing specialization on the IR itself Just Work with global generic value parameters since they already support value parameters on explicit generic declarations.

That's the santized version of things, but there were also a bunch of cleanups and tweaks required along the way:

* The `SpecializationParam` type was extended to also track a `SourceLoc` to help in diagnostic messages, which meant some churn in the code that collects specialization parameters.

* The `_extractSpecializationArgs` function is tweaked to support any kind of "term" as a specialization argument (either a type or a value).

* To allow *parsing* specialization arguments that can't possibly be types (e.g., integer literals) we replace the existing `parseTypeString` routine with `parseTermString` and then in `parseTermFromSourceFile` call through to a general case of expression parsing (which can also parse types) rather than only parsing types directly.

* Right before doing back-end code generation, we check if the program we are going to emit has remaining (unspecialized) parameters, in which case we emit a diagnostic message for the parameters that haven't been specialized rather than go on to emit code that will fail to compile downstream.

* Within the `render-test` tool we collapse down the arrays that held both "generic" and "existential" specialization arguments, so that we just have *global* and *entry-point* specialization argument lists. This mirrors how Slang has worked internally for a while, but the difference hasn't been important to the test tool because no tests currently mix generic and existential specialization. The logic for parsing `TEST_INPUT` lines has been streamlined down to just the global and entry-point cases, but the pre-existing keywords are still allowed so that I don't have to tweak any test cases.

There are several significant caveats for this feature, which mean that it isn't really ready for users to hammer on just yet:

* There is no support for `Val`s of anything but integers, so there is no way to meaningfully have a generic value param with a type other than `int` or `uint`.

* We allow for a default-value expression on global generic parameters, but do not actually make use of that value for anything (e.g., to allow a programmer to omit specialization arguments), nor check that it meets the constraints of being compile-time constant.

* Global generic value parameters are *not* currently being treated the same as explicit generic parameters in terms of how they can be used for things like array sizes or other things that require constants. This will probably be relaxed at some point, but allowing a global generic to be used to size an array creates questions around layout.

* The IR optimization passes in Slang currently won't eliminate entire blocks of code based on constant values, so using a global generic value parameter to enable/disable features will *not* currently lead to us outputting drastically different HLSL or GLSL. That said, we expect most downstream compilers to be able to handle an `if(0)` well.

* Fix regression for tagged union types

The change that made specialization arguments be parsed as "terms" first, and then coerced to types meant that any special-case logic that is specific to the parsing of types would be bypassed and thus not apply.
Most of that special-case logic isn't wanted for specialization arguments, since it pertains to cases were we want to, e.g, declare a `struct` type while also declaring a variable of that type.
The one special case that *is* useful is the `__TaggedUnion(...)` syntax, which is the only way to introduce a tagged union type right now.

In order to get that case working again, all I had to do was register the existing logic for parsing `__TaggedUnion` as an expression keyword with the right callback, and the existing logic in expression parsing kicks in (that logic was already handling expression keywords like `this` and `true`).

I left in the existing logic for handling `__TaggedUnion` directly where types get parsed, rather than try to unify things.
A better long-term fix is to make the base case for type parsing route into `parseAtomicExpr` so that the two paths share the core logic.
That change should probably come as its own refactoring/cleanup, because it creates the potential for some subtle breakage.

* fixup: typo
1 parent dd43551
History
Tip revision: fae3d9ae91a24e59ce6ec64b8a1217fa81f5acee authored by Tim Foley on 19 November 2019, 21:53:52 UTC
Initial work for "global generic value parameters" (#1127)
Tip revision: fae3d9a
File Mode Size
docs
examples
external
prelude
source
tests
tools
.editorconfig -rw-r--r-- 937 bytes
.gitattributes -rw-r--r-- 95 bytes
.gitignore -rw-r--r-- 480 bytes
.gitmodules -rw-r--r-- 774 bytes
.travis.yml -rw-r--r-- 1.7 KB
CODE_OF_CONDUCT.md -rw-r--r-- 3.1 KB
LICENSE -rw-r--r-- 1.1 KB
README.md -rw-r--r-- 7.1 KB
appveyor.yml -rw-r--r-- 4.0 KB
premake5.lua -rw-r--r-- 28.3 KB
slang-com-helper.h -rw-r--r-- 4.8 KB
slang-com-ptr.h -rw-r--r-- 4.8 KB
slang-tag-version.h -rw-r--r-- 36 bytes
slang.h -rw-r--r-- 120.6 KB
slang.sln -rw-r--r-- 9.9 KB
test.bat -rw-r--r-- 1.4 KB
travis_build.sh -rw-r--r-- 460 bytes
travis_test.sh -rw-r--r-- 435 bytes

README.md

back to top