diff options
| author | Tim Foley <tfoleyNV@users.noreply.github.com> | 2020-04-08 09:41:59 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-04-08 09:41:59 -0700 |
| commit | a53f817623c917887926d3601cfa88906d6d52b9 (patch) | |
| tree | 1177c4733199480c3bc30b6e0eaaa1e40faec2e2 /tests | |
| parent | a9214f34358b2fc0bf61ef90e3719a13b180b423 (diff) | |
Fixes for IR generics (#1311)
* Fixes for IR generics
There are a few different fixes going on here (and a single test that covers all of them).
1. Fix optionality of trailing semicolon for `struct`s
======================================================
We have logic in the parser that tries to make a trailing `;` on a `struct` declaration optional. That logic is a bit subtle and couild potentially break non-idiomatic HLSL input, so we try to only trigger it for files written in Slang (and not HLSL). For command-line `slangc` this is based on the file extension (`.slang` vs. `.hlsl`), and for the API it is based on the user-specified language.
The missing piece here was that the path for handling `import`ed code was *not* setting the source language of imported files at all, and so those files were not getting opted into the Slang-specific behavior. As a result, `import`ed code couldn't leave off the semicolon.
2. Fix generic code involving empty `interface`s
================================================
We have logic that tries to only specialize "definitions," but the definition-vs-declaration distinction at the IR level has historically been slippery. One corner case was that a witness table for an interface with no methods would always be considered a declaration, because it was empty. The notion of what is/isn't a definition has been made more nuanced so that it amounts to two main points:
* If something is decorated as `[import(...)]`, it is not a definition
* If something is a generic/func (a declaration that should have a body), and it has no body, it is a declaration
Otherwise we consider anything a definition, which means that non-`[import(...)]` witness tables are now definitions whether or not they have anything in them.
3. Fix IR lowering for members of generic types
===============================================
The IR lowering logic was trying to be a little careful in how it recurisvely emitted "all" `Decl`s to IR code. In particular, we don't want to recurse into things like function parameters, local variables, etc. since those can never be directly referenced by external code (they don't have linkage).
The existing logic was basically emitting everything at global scope, and then only recursing into (non-generic) type declarations. This created a problem where a method declared inside a generic `struct` would not be emitted to the IR for its own module at all *unless* it happened to be called by other code in the same module.
The fix here was to also recurse into the inner declaration of `GenericDecl`s. I also made the code recurse into any `AggTypeDeclBase` instead of just `AggTypeDecl`s, which means that members in `extension` declarations should not properly be emitted to the IR.
Conclusion
==========
These fixes should clear up some (but not all) cases where we might emit an `/* unhandled */` into output HLSL/GLSL. A future change will need to make that path a hard error and then clean up the remaining cases.
* fixup: tabs->spaces
Diffstat (limited to 'tests')
3 files changed, 86 insertions, 0 deletions
diff --git a/tests/language-feature/generics/struct-generic-value-param-import.slang b/tests/language-feature/generics/struct-generic-value-param-import.slang new file mode 100644 index 000000000..edc1b0c39 --- /dev/null +++ b/tests/language-feature/generics/struct-generic-value-param-import.slang @@ -0,0 +1,19 @@ +// struct-generic-value-param-import.slang +//TEST_IGNORE_FILE: + +// This file is used by `struct-generic-value-param.slang`, +// and also incidentally tests that a trailing `;` is optional +// for `struct` decalrations in Slang files, including +// any `import`ed code. + +interface IData {} + +struct Data<let kCount : int> : IData +{ + int state; + + [mutating] void doStuff() + { + state++; + } +} diff --git a/tests/language-feature/generics/struct-generic-value-param.slang b/tests/language-feature/generics/struct-generic-value-param.slang new file mode 100644 index 000000000..857468165 --- /dev/null +++ b/tests/language-feature/generics/struct-generic-value-param.slang @@ -0,0 +1,63 @@ +// struct-generic-value-param.slang + +// This test reproduces a few bugs related to declarations +// not being emitted IR and specialized correctly. +// +// First, it tests that a method in a generic `struct` +// gets properly emitted to the IR of its own module. +// +// Second, it tests that witness tables for an empty +// `interface` can be emitted and used to specialize +// code with generic type parameters constrained to +// those interfaces. + +// This file is attempting to stress-test use of a `struct` +// type with a generic value parameter. In particular, it +// it can reproduce a bug that was encountered by a user +// when trying out the feature. + +//TEST(compute):COMPARE_COMPUTE: + +import struct_generic_value_param_import; + +Data<N> makeData<let N : int>( int val ) +{ + Data<N> result = { val }; + return result; +} + +void doThings<D : IData>(D data, inout int v) +{ + v++; +} + +int test(int val) +{ + var data = makeData<4>(val); + + // Note: with the original bug, this call emitted + // as `/* unhandled */(data)` which meant the call + // acted as a no-op. + // + data.doStuff(); + + // Note: with the original bug, this call emitted + // as `/* uhandled */(data, val)` which is also + // a no-op (that happens to use `operator,`). + // + doThings(data, val); + + return data.state + val*16; +} + +//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name=outputBuffer +RWStructuredBuffer<int> outputBuffer; + +[numthreads(4, 1, 1)] +void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) +{ + uint tid = dispatchThreadID.x; + int inVal = tid; + int outVal = test(inVal); + outputBuffer[tid] = outVal; +} diff --git a/tests/language-feature/generics/struct-generic-value-param.slang.expected.txt b/tests/language-feature/generics/struct-generic-value-param.slang.expected.txt new file mode 100644 index 000000000..e4511c4c7 --- /dev/null +++ b/tests/language-feature/generics/struct-generic-value-param.slang.expected.txt @@ -0,0 +1,4 @@ +11 +22 +33 +44 |
