| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
packing/unpacking. (#8526)
Part of the effort to improve the performance of generated SPIRV code.
The existing lower-buffer-element-type pass works by loading the entire
buffer element content from memory, and translate it to logical type
stored in a local variable at the earliest reference of a buffer handle.
This means that is can generate inefficient code that reads more than
necessary.
Consider this example:
```
struct BigStruct { bool values[1024]; }
ConstantBuffer<BigStruct> cb;
void test(BigStruct v)
{
if (v.values[0]) { printf("ok"); }
}
[numthreads(1,1,1)]
void computeMain()
{
test(cb);
}
```
In IR, the `computeMain` function before lower-buffer-element-type pass
is something like following:
```
func test:
%v = param : BigStruct
%barr = fieldExtract(%v, "values")
%element = elementExtract(%barr, 0)
... // uses %element
func computeMain:
%v = load(cb)
call %test %v
```
The existing lower-buffer-element-type pass will rewrite the bool array
in `BigStruct` into `int` array so it is legal in SPIRV. However, it
does so by inserting the translation on the first `load` of the constant
buffer:
```
struct BigStruct_std430 {
int values[1024];
}
var cb : ConstantBuffer<BigStruct_std430>;
func computeMain:
%tmpVar : var<BigStruct>
call %unpackStorage(%tmpVar, cb)
%v : BigStruct = load %tmpVar
call %test %v
```
This means that the entire array will be loaded and translated to int,
before calling `test`, which only uses one element. It turns out that
the downstream compiler isn't always able to optimize out this
inefficient translation/copy.
This PR completely rewrites the way buffer-element-type lowering is
handled to avoid producing this inefficient code. It works in two parts:
first we turn on the `transformParamsToConstRef` pass for SPIRV target
as well, so we will translate the `test` function to take the `v`
parameter as `constref`. The second part is a redesigned
buffer-element-type pass that defers the storage-type to logical-type
translation until a value is actually used by a `load` instruction.
In this example, after `transformParamsToConstRef`, the IR is:
```
func test:
%v = param : ConstRef<BigStruct>
%barr = fieldAddr(%v, "values")
%elementPtr = elementAddr(%barr, 0)
%element = load(%elementPtr)
... // uses %element
func computeMain:
call %test %cb
```
The new `buffer-element-type-lowering` pass will take this IR, and
insert translation at latest possible time across the entire call graph,
and translate the IR into:
```
func test:
%v = param : ConstRef<BigStruct_std430>
%barr = fieldAddr(%v, "values")
%elementPtr : ptr<int> = elementAddr(%barr, 0)
%element_int = load(%elementPtr)
%element = cast(%element_int) : %bool
... // uses %element
func computeMain:
call %test %cb
```
In this new IR, there is no longer a load and conversion of the entire
array.
See new comment in `slang-ir-lower-buffer-element-type.cpp` for more
details of how the pass works.
This PR also address many other issues surfaced by turning on
`transformParamsToConstRef` pass on SPIRV backend.
---------
Co-authored-by: slangbot <186143334+slangbot@users.noreply.github.com>
|
|
|
* Add noreturn attribute to IgnoreHit
* Revert "Add noreturn attribute to IgnoreHit"
This reverts commit 3cf2354dada71b9a8713b08f3a2e261de4aabfa4.
* Fix: Preserve inout param modifications with OptiX IgnoreHit()
Issue #6326 identified that in OptiX, when using IgnoreHit() (which
maps to the "noreturn" optixIgnoreIntersection() intrinsic), any
modifications made to 'inout' parameters within the shader would be
lost. This was due to IgnoreHit() preventing the execution of the
copy-back operation from the temporary variable (used to implement
'inout' semantics) to the original parameter.
This commit introduces a new IR pass, 'undoParameterCopy', specifically
for CUDA/OptiX targets to address this. The pass operates as follows:
1. Identifies temporary IR variables created for 'inout' parameters,
which are now decorated with 'TempCallArgVarDecoration'.
2. Maps these temporary variables back to their original parameter
storage (e.g., the OptiX payload pointer).
3. Replaces all uses of the temporary variable directly with the
original parameter pointer.
4. Removes the temporary variable declaration and its initializing store
(which copied from the original parameter to the temporary).
By transforming the IR to operate directly on the original parameter
storage before any potential call to IgnoreHit(), this fix ensures
that all modifications are preserved, correctly resolving issue #6326.
The pass is integrated into the compilation flow for relevant targets.
* Refactor(IR): Optimize GetOptiXRayPayloadPtr for better DCE/CSE
To allow for more effective dead code elimination (DCE) and
common subexpression elimination (CSE) of `getOptiXRayPayloadPtr`
instructions, this commit:
- Marks `kIROp_GetOptiXRayPayloadPtr` as side-effect-free within
`IRInst::mightHaveSideEffects` (in `slang-ir.cpp`).
- Flags `GetOptiXRayPayloadPtr` as `HOISTABLE` in its definition
within `slang-ir-inst-defs.h`.
This addresses scenarios where multiple, potentially redundant,
calls to `getOptiXRayPayloadPtr` might appear in the IR,
allowing optimizers to produce cleaner and potentially more
efficient code for OptiX targets. This change supports efforts
to refine IR handling for ray-tracing shader stages.
* Remove debugging code
* Refactor UndoParameterCopyVisitor for improved performance
- Optimized IR traversal by combining multiple passes into a single scan
- Removed unnecessary dictionary, immediately replace uses when a temp var is found
- Reduced duplicate code paths by checking for both temp vars and redundant stores in one loop
- Better handling of the 'changed' flag to ensure DCE only runs when needed
- Results in fewer instruction traversals and improved efficiency for large functions
* Add Test
|