<table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Issue</th>
<td>
<a href=https://github.com/llvm/llvm-project/issues/99173>99173</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>
Implement the `WavePrefixProduct` HLSL Function
</td>
</tr>
<tr>
<th>Labels</th>
<td>
metabug,
backend:DirectX,
HLSL,
backend:SPIR-V,
bot:HLSL
</td>
</tr>
<tr>
<th>Assignees</th>
<td>
</td>
</tr>
<tr>
<th>Reporter</th>
<td>
farzonl
</td>
</tr>
</table>
<pre>
- [ ] Implement `WavePrefixProduct` clang builtin,
- [ ] Link `WavePrefixProduct` clang builtin with `hlsl_intrinsics.h`
- [ ] Add sema checks for `WavePrefixProduct` to `CheckHLSLBuiltinFunctionCall` in `SemaChecking.cpp`
- [ ] Add codegen for `WavePrefixProduct` to `EmitHLSLBuiltinExpr` in `CGBuiltin.cpp`
- [ ] Add codegen tests to `clang/test/CodeGenHLSL/builtins/WavePrefixProduct.hlsl`
- [ ] Add sema tests to `clang/test/SemaHLSL/BuiltIns/WavePrefixProduct-errors.hlsl`
- [ ] Create the `int_dx_WavePrefixProduct` intrinsic in `IntrinsicsDirectX.td`
- [ ] Create the `DXILOpMapping` of `int_dx_WavePrefixProduct` to `121` in `DXIL.td`
- [ ] Create the `WavePrefixProduct.ll` and `WavePrefixProduct_errors.ll` tests in `llvm/test/CodeGen/DirectX/`
- [ ] Create the `int_spv_WavePrefixProduct` intrinsic in `IntrinsicsSPIRV.td`
- [ ] In SPIRVInstructionSelector.cpp create the `WavePrefixProduct` lowering and map it to `int_spv_WavePrefixProduct` in `SPIRVInstructionSelector::selectIntrinsic`.
- [ ] Create SPIR-V backend test case in `llvm/test/CodeGen/SPIRV/hlsl-intrinsics/WavePrefixProduct.ll`
## DirectX
| DXIL Opcode | DXIL OpName | Shader Model | Shader Stages |
| ----------- | ----------- | ------------ | ------------- |
| 121 | WavePrefixOp | 6.0 | ('library', 'compute', 'amplification', 'mesh', 'pixel', 'vertex', 'hull', 'domain', 'geometry', 'raygeneration', 'intersection', 'anyhit', 'closesthit', 'miss', 'callable', 'node') |
## SPIR-V
# [OpGroupNonUniformFMul](https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#OpGroupNonUniformFMul):
## Description:
A floating point multiply [group operation](https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#Group_Operation) of all
*Value* operands contributed by active [invocations](https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#Invocation) in the
[group](https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#Group).
*Result Type* must be a scalar or vector of [*floating-point
type*](https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#Floating).
*Execution* is a [*Scope*](https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#Scope_-id-) that identifies the group of
invocations affected by this command. It must be **Subgroup**.
The identity *I* for *Operation* is 1. If *Operation* is
**ClusteredReduce**, *ClusterSize* must be present.
The type of *Value* must be the same as *Result Type*. The method used
to perform the group operation on the contributed *Value*(s) from active
invocations is implementation defined.
*ClusterSize* is the size of cluster to use. *ClusterSize* must be a
scalar of [*integer type*](https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#Integer), whose *Signedness* operand is 0.
*ClusterSize* must come from a [*constant
instruction*](https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#ConstantInstruction). Behavior is undefined unless
*ClusterSize* is at least 1 and a power of 2. If *ClusterSize* is
greater than the size of the [group](https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#Group), executing this instruction
results in undefined behavior.
[Capability](https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#Capability):
**GroupNonUniformArithmetic**, **GroupNonUniformClustered**,
**GroupNonUniformPartitionedNV**
[Missing before](https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#Unified) **version 1.3**.
<table>
<colgroup>
<col style="width: 12%" />
<col style="width: 12%" />
<col style="width: 12%" />
<col style="width: 12%" />
<col style="width: 12%" />
<col style="width: 12%" />
<col style="width: 12%" />
<col style="width: 12%" />
</colgroup>
<thead>
<tr>
<th>Word Count</th>
<th>Opcode</th>
<th>Results</th>
<th>Operands</th>
<th></th>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p>6 + variable</p></td>
<td class="tableblock halign-left valign-top"><p>352</p></td>
<td
class="tableblock halign-left valign-top"><p><em><id></em><br />
<em>Result Type</em></p></td>
<td class="tableblock halign-left valign-top"><p><a
href="#ResultId"><em>Result <id></em></a></p></td>
<td class="tableblock halign-left valign-top"><p><a
href="#Scope_-id-"><em>Scope <id></em></a><br />
<em>Execution</em></p></td>
<td class="tableblock halign-left valign-top"><p><a
href="#Group_Operation"><em>Group Operation</em></a><br />
<em>Operation</em></p></td>
<td
class="tableblock halign-left valign-top"><p><em><id></em><br />
<em>Value</em></p></td>
<td class="tableblock halign-left valign-top"><p>Optional<br />
<em><id></em><br />
<em>ClusterSize</em></p></td>
</tr>
</tbody>
</table>
## Test Case(s)
### Example 1
```hlsl
//dxc WavePrefixProduct_test.hlsl -T lib_6_8 -enable-16bit-types -O0
export float4 fn(float4 p1) {
return WavePrefixProduct(p1);
}
```
### Example 2
```hlsl
//dxc WavePrefixProduct_1_test.hlsl -T lib_6_8 -enable-16bit-types -O0
export uint4 fn(uint4 p1) {
return WavePrefixProduct(p1);
}
```
### Example 3
```hlsl
//dxc WavePrefixProduct_2_test.hlsl -T lib_6_8 -enable-16bit-types -O0
export int4 fn(int4 p1) {
return WavePrefixProduct(p1);
}
```
## HLSL:
Returns the product of all of the values in the active lanes in this wave with indices less than this lane.
## Syntax
``` syntax
<type> WavePrefixProduct(
<type> value
);
```
## Parameters
*value*
The value to multiply.
## Return value
The product of all the values.
## Remarks
The order of operations on this routine cannot be guaranteed. So, effectively, the \[precise\] flag is ignored within it.
A postfix product can be computed by multiplying the prefix product by the current lane's value.
Note that the active lane with the lowest index will always receive a 1 for its prefix product.
This function is supported from shader model 6.0 in all shader stages.
## Examples
```hlsl
uint numToMultiply = 2;
uint prefixProduct = WavePrefixProduct( numToMultiply );
```
On a machine with a wave size of 8, and all lanes active except lanes 0 and 4, the following values would be returned from WavePrefixProduct.
| lane index | status | prefixProduct |
|------------|----------|---------------|
| 0 | inactive | n/a |
| 1 | active | = 1 |
| 2 | active | = 1\*2 |
| 3 | active | = 1\*2\*2 |
| 4 | inactive | n/a |
| 5 | active | = 1\*2\*2\*2 |
| 6 | active | = 1\*2\*2\*2\*2 |
| 7 | active | = 1\*2\*2\*2\*2\*2 |
## See also
[Overview of Shader Model 6](https://github.com/MicrosoftDocs/win32/blob/docs/desktop-src//direct3dhlsl/hlsl-shader-model-6-0-features-for-direct3d-12.md)
[Shader Model 6](https://github.com/MicrosoftDocs/win32/blob/docs/desktop-src//direct3dhlsl/shader-model-6-0.md)
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzsWl1T47jS_jXiRhWXI5MELrgwgeybqplhapid3TtKsduxXmTJJcmBzK8_1ZIdOx_AzOyyey4ORYHVkvrj6W5ZaplbK9YK4IpMrsnk5ow3rtTmquDmu1bybKXz7dWIksk1JZMbuqxqCRUoR8k0_oNv4LOBQjx_NjpvMkemMc0kV2u6aoR0QhE2J3HaT_8g1OOPzaRPwpU4tJRWPgjljFBWZDYqyTTe45nmObVQcZqVkD1aWmjzoginsWuOA__vw_2H6yBr0ajMCa3mXEocJRSOuoeK-5FCraOsrk_JzXQOa1A_IPO2Em4g8va5Nr2o-W8t-S05DqyzLUcPF2ELpBG2mOscfgOFMghbtChawhZHSkUI6YsoviICEWn5e32Xp_mPwBht7EkxcwPcAXUlIH-h3EP-_HAStp3LW4yWuxC4EQYy92fk8te53_y5_HBXf-R1LdQaWeriLaFOUxwyZuPeOcjmdVknXR-FWOIqP9n90IIURgXQgzwpN9WRWwlbtGYTtngbVFtvfhbV-8_LL99O2LlU1HctlXWm8XlyDxIypw1GK832hJ8UKvUTGKHWHoyK15QK10bYG8r6PHxBOklSkqTWt3ZmkGkcncIGmYy-0RXPHkHlHm-acQtvYO5lE7bAUB71i9DJrJJtsOMvSwhLaOexQJvNKYYSvasxm-mg_YlXoX1f8hwM_ahzkEPCveNrsEhpGY36H_pG-5gwGjAas7Hv7825qz1hGsX-P2EXhM2kWBlutoTNCEPaLNNV3TjoCbyqpShExtFFPbkCW_atWjyD7JsbMA6e-3bZyEFvrisuBqzWoCtwQyUM365BgTmQKZQDYyHbp3K1LYUbWCC1Bev2aJWwdjCCS8lXcmCk0nloXXYQ7nwdAmxHwvi7q38zuqk_afW7EoU21eJjI8nkhrCL0rnaYgCzBWELA2thndlGj6XRSttIm3UbfCOMPluDj7lGiUJAPu4CMypdJQlLTgtilyhgLx7BZkbUHhffRSmJ05QWUnOH-VlroRytGulELbdowxoZU113IL-D9l73h7udCHaJCzW-ilHx9BuXDRCWBiVUbmmmMRFXjYOcrraUZ05sAJUVaqNDANr3UHS5Y486CoVrHurYovRu2BB2GXlP-T-EpV_ANtLRr9vaA1M11tEVUE5txiU3VBu68Uukf-NNrglLOxePvItJnLow-T2UXrSyjvS-fYasCfilVFjKW-XuM_1uynjeDyORj9BpruSOihyUw9HWv7XaEC9InA4CiPKigKwNMVcKDLuq4iqP6NLtIEelWXrfrEIE-NbA5q8ltNLcFscu0XC_V2TpIOA9GOOILosTHQE6wtK5bKwDA_kXyJsMAjEsTF3fvfi-FxG1AQvKHWiErveRMUiubgYCYvF1xC09irSI4vQKXKlz2ljIMY40rcHgojMEszOBap8leyk7EEvYhUW3FEZXbR4feEFYKrojR-CYQyEU5PuRdWC_CJ614rs3NAu9uOVoLESvAMZJnHZJ1KUOvk7WOPv9MmYZROCSzeb0qdTWh9Y9HsxyBfhS2q1_aJzf47xgRaYraAFtDci0so77rBf9NuqdTJm3wpZDSZcRvYaSb4Q2qH6jWifSRkm07gUfckclcOvo2O8cOa1xI4meYV2yHE0icbr2Wz6Dya724sDvUf-B1RqdCGGtU-uweAyBj1Pj08pv-HssVi1CUfvOnlzPec1XQgq3fRdP9dz9VqHLJcLSg-1EaoQrK3Ai21t0jgfulqjduJdYfubGCUQD8k_fwohBQk-uPwprEbwVFNrAe5j_e6D7vZyXvwFjcYEZR0m7kLeOSObObwOT29DKtAwhNCBQ67Y45IYw9iRyVyKgY0bYhDBGUeP_Df7LgwlbHGHvSuB53zKDDpLc_qFNTue6US5M98RBfziLne4L7z770sSwGT3d-w5UbJm91r7hK51vT8KQ00xyawO-PpBXUmePtORSrNVIQuHoJjw7XRPGgnREeEoJu6YbbkSIfxRb98rlf4uQZMJe5Uzi9Jd5k2QOFf5nU-lIci1ywqZrfAqCQmcyX5m9OPPk4dZnb_B7gECSOW49SgNFmE5YEhRY5ruBQ7XesoiwBf9n1R1utIcKe_pP6HvKF_3B4V_xxNEJdWif76R950-Y9fKk_7JcCPv1d8f-zpcmuHxBi1_RfLg__CH9j9fZvZUVCYPNQLxfYPkK1tE5t9AebEKn39eEETjo9pnjiYaOsXcah19fK4_brU3-nNHjgrEDG0r3dPSVSrF6mD5c0BEoVGc0nq6EG-ERxdLRXVuGhOdaGxfKO-e0UIRdtM_1ONSwrv2Wi1IDrjHqWChhF34oYh2nZHYz1Pm0WewnzRr_umGNUJ1d4fEdzUp-0iz262b1Vv2tRrUG-QucrjD4xfMKp-U6sGmLb915aYOpb9tqV1drk1x1NGHpE99AuK4TKhcZWIqHuu74JawfHu1XS7fK8eeW1OlI7Y6azP1pO7k9aWY4J8wZSePBSK-pF9FBMDR-J_ozN7wCB8Z25HTTVUEC5WtnNnV6Vwzd1z_g1osMkw4Q7OE7nFxx82j7edrk4Vi7q5vYUDgRlhqNp0igGVdK-xrFuuGGKweQR_Re-7OmL1WJDcgtNsMxd04m17WBTFjwjRtaSL72BZW10gZy7zKhqHCteimttXWFeN4ZknGFEttivy-FdXiEk60vMQ1n-GIZ0KwxBpTznidsZgMOrZxP2t8XcXcYUiGIkCj1Ey6lQuXwTJ-ElJTLJ7611EAGOJzTsS-kCWcPVIg6XIWlRXuxi1bbpsbsgjwUR2y4Wan8Vcs08pdN6LSWbv2NS0T3HNeuBfYgbtvVAJcgqprqq_64K6AnN5SFYPS99TCQfe-p8D5k8kI83ynKacWzUnTI8ZCKXbnjAoPBF06kbFO2BRueM6hdSwt3lOdd5BRaSv2E7m1T_0k3MscwCAtPB-DxBVh_z-WdGZyHTeu4ayylvnGAwWxOw6ThBdVe86AvUFpBMd39YFOo7jJgNqcKN190b0B36bU_q50TGuiU8clZ7K1ZmGYsZcczkx-cOWTQzz7_JRsnPydzX_eezfSX2Ay49axmf4VVx_Ho2g2Acmn1rmZ2twGzEfCECbB3nTo9VURaC1c2qyjTFWGLjyIz2urC3WhfOXoSKmGELVZSr_A9H6g52Een65E1Wfv-97e8Se6XgfaqOKwiI7-6jKajeFQAd40BOyq0GXUzRmMWVflun0gm1_-KxofKBp3O8qskv0wu-RlcjWdsPJ7Gk3F8Vl4lqzieTMcMioLFcVLkPJ7E0_HFRXE-ns3yyzNxxWJ2Hs_GUxbHF0kcTS5ns9kKxtPx-SyGVUzOY6i4kJGUmyrSZn0mrG3g6vJyPEvOJF-BtP5zJMYqcHzVrP05bE4Yay_wSZLuPodoe8KHKUfDunpg16EdSdJu7OTmzFyhEqNVs7bkPJbCOtur5YSTcNV_8_TaRw7Ik3ZfEp01Rl694rj2ewMvujb6_wEX_oVHAT0WgNhcsf8EAAD__21PXa0">