<table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Issue</th>
<td>
<a href=https://github.com/llvm/llvm-project/issues/99176>99176</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>
Implement the `QuadReadAcrossY` 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 `QuadReadAcrossY` clang builtin,
- [ ] Link `QuadReadAcrossY` clang builtin with `hlsl_intrinsics.h`
- [ ] Add sema checks for `QuadReadAcrossY` to `CheckHLSLBuiltinFunctionCall` in `SemaChecking.cpp`
- [ ] Add codegen for `QuadReadAcrossY` to `EmitHLSLBuiltinExpr` in `CGBuiltin.cpp`
- [ ] Add codegen tests to `clang/test/CodeGenHLSL/builtins/QuadReadAcrossY.hlsl`
- [ ] Add sema tests to `clang/test/SemaHLSL/BuiltIns/QuadReadAcrossY-errors.hlsl`
- [ ] Create the `int_dx_QuadReadAcrossY` intrinsic in `IntrinsicsDirectX.td`
- [ ] Create the `DXILOpMapping` of `int_dx_QuadReadAcrossY` to `123` in `DXIL.td`
- [ ] Create the `QuadReadAcrossY.ll` and `QuadReadAcrossY_errors.ll` tests in `llvm/test/CodeGen/DirectX/`
- [ ] Create the `int_spv_QuadReadAcrossY` intrinsic in `IntrinsicsSPIRV.td`
- [ ] In SPIRVInstructionSelector.cpp create the `QuadReadAcrossY` lowering and map it to `int_spv_QuadReadAcrossY` in `SPIRVInstructionSelector::selectIntrinsic`.
- [ ] Create SPIR-V backend test case in `llvm/test/CodeGen/SPIRV/hlsl-intrinsics/QuadReadAcrossY.ll`
## DirectX
| DXIL Opcode | DXIL OpName | Shader Model | Shader Stages |
| ----------- | ----------- | ------------ | ------------- |
| 123 | QuadOp | 6.0 | ('library', 'compute', 'amplification', 'mesh', 'pixel', 'node') |
## SPIR-V
# [OpGroupNonUniformQuadSwap](https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#OpGroupNonUniformQuadSwap):
## Description:
Swap the *Value* of the [invocation](https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#Invocation) within the
[quad](https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#Quad) with another invocation in the quad using *Direction*.
*Result Type* must be a scalar or vector of [*floating-point
type*](https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#Floating), [*integer type*](https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#Integer), or [*Boolean
type*](https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#Boolean).
*Execution* is a [*Scope*](https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#Scope_-id-), but has no effect on the
behavior of this instruction. It must be **Subgroup**.
The type of *Value* must be the same as *Result Type*.
*Direction* is the kind of swap to perform.
*Direction* must be a scalar of [*integer type*](https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#Integer), whose
*Signedness* operand is 0.
*Direction* must come from a [*constant
instruction*](https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#ConstantInstruction).
The value returned in *Result* is the value provided to *Value* by
another invocation in the same quad scope instance. The invocation
providing this value is determined according to *Direction*.
A *Direction* of 0 indicates a horizontal swap;
- Invocations with [quad indices](https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#QuadIndex) of 0 and 1 swap values
- Invocations with [quad indices](https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#QuadIndex) of 2 and 3 swap values
A *Direction* of 1 indicates a vertical swap;
- Invocations with [quad indices](https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#QuadIndex) of 0 and 2 swap values
- Invocations with [quad indices](https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#QuadIndex) of 1 and 3 swap values
A *Direction* of 2 indicates a diagonal swap;
- Invocations with [quad indices](https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#QuadIndex) of 0 and 3 swap values
- Invocations with [quad indices](https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#QuadIndex) of 1 and 2 swap values
*Direction* must be one of the above values.
If an active invocation reads *Value* from an inactive invocation, the
resulting value is undefined.
[Capability](https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#Capability):
**GroupNonUniformQuad**
[Missing before](https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#Unified) **version 1.3**.
<table style="width:100%;">
<colgroup>
<col style="width: 14%" />
<col style="width: 14%" />
<col style="width: 14%" />
<col style="width: 14%" />
<col style="width: 14%" />
<col style="width: 14%" />
<col style="width: 14%" />
</colgroup>
<thead>
<tr>
<th>Word Count</th>
<th>Opcode</th>
<th>Results</th>
<th>Operands</th>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p>6</p></td>
<td class="tableblock halign-left valign-top"><p>366</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><em><id></em><br />
<em>Value</em></p></td>
<td
class="tableblock halign-left valign-top"><p><em><id></em><br />
<em>Direction</em></p></td>
</tr>
</tbody>
</table>
## Test Case(s)
### Example 1
```hlsl
//dxc QuadReadAcrossY_test.hlsl -T lib_6_8 -enable-16bit-types -O0
export float4 fn(float4 p1) {
return QuadReadAcrossY(p1);
}
```
### Example 2
```hlsl
//dxc QuadReadAcrossY_1_test.hlsl -T lib_6_8 -enable-16bit-types -O0
export uint4 fn(uint4 p1) {
return QuadReadAcrossY(p1);
}
```
### Example 3
```hlsl
//dxc QuadReadAcrossY_2_test.hlsl -T lib_6_8 -enable-16bit-types -O0
export int4 fn(int4 p1) {
return QuadReadAcrossY(p1);
}
```
## HLSL:
Returns the specified source value read from the other lane in this quad in the Y direction.
## Syntax
``` syntax
<type> QuadReadAcrossY(
<type> localValue
);
```
## Parameters
<dl> <dt>
*localValue*
</dt> <dd>
The requested type.
</dd> </dl>
## Return value
The specified source value. If the source lane is inactive, the results are undefined.
## Remarks
For more information on quads, refer to [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).
This function is supported from shader model 6.0 only in pixel and compute shaders.
## See also
<dl> <dt>
[Shader Model 6](https://github.com/MicrosoftDocs/win32/blob/docs/desktop-src//direct3dhlsl/shader-model-6-0.md)
</dt> </dl>
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzsWl9z2zYS_zTwC4YaCrQk68EPlGz1NJM0vTjttU8ekFiJOIMAC4Cy3U9_swAlUrFsN7364ofrZGpysdg_v10ssKC4c3KrAS7JZEEmV2e89ZWxlxtu_zBanRVGPF4mlEwWlEyu6LpuFNSgPSXT9J8tF5-Bi7y0xrnfyDSlpeJ6S4tWKi81YUuS5v3kD1Lf_Zl59F76Chkr5dSt1N5K7WTpRhWZpkcScyGog5rTsoLyztGNsc8o8AYHlsj2jw83HxZR06rVpZdGL7lSyCU1ct1AzQOn1NtR2TSntJZGwBb0qxqva-kHCq8fGtsrWv7QkV_T4sF510kMUBG2Qhphq6UR8ANo1EHYqkPQEbb6yqQRgvksfi8oQDQ66cHa9SnpCVhrrDupZGmBe6C-ApQutb8VD7cnADsEukNnfQj8lbRQ-l9HXrws--rX9YdPzUfeNFJvUaTZvKzSG4oMY5b1QUEhL2s6EfBRzB-uxYnB2w6cyBOhjrqU2tVPQknYqnOYsNXrYLpm921o3vy0_vzLCQ_XmoahtXbetmFd3ICC0huL-UnLI9UnVCpzD1bqbYCh5g2l0nc59aKhYc09o5lkOclyF94OLpBpOjqFCgpJfqEFL-9Ai4A0LbmDV9AOuglbYfImfbk5sYZUl9z4j2WEZXQfqUibLSmmD_3U4Mqlg_cfeR3fbyouwNKPRoAaEm4834JDSico6f-jr7w_JSQDQWOWhXF05lMTHqejNPwl7IKwmZKF5faRsBlhSJuVpm5aDz2B142SG1lyDE1PrsFV_VsjH0D1r9qIKGG-t-UAWozTgYRh_NT8YE3b_Gj0z1pujK3R2pt73pDJFWEXlfeNw1xgK8JWFrbSefs4uqus0caNjN12cUwwkK6BEL5Wy40EMd7HeFT5WhGWPa-MzVHJUYDBlVY2wfEwRClJc2SOK4Hlv3DVAmE5VptAmiyk3pkOrDcwf91LZ_OwWUqNmtHoyeL3lou30IoY7fVRro2vwNLeURptoKietg7LAGF5XB7B0nwUkAv_Iyz_DK5Vnn55bAJ2des8LYBy6kquuKXG0l2oAKGITxaE5RtluJd6mzRGak_S3MfJb-HtqtOFGYH5HAyQ2sMWLH1DveuoolOLh4ugeWGMAq7f1ue9EjY_DtX1A5RtF0QqHeWdUTeleTNbguzbRIqkg6JoPa24o9pQ2Gyg9NTsk76Aiu9kzBRfSdxcD_vIiK79IbnQVpbftMUWl398G7j6pYIQ2pBxg3W9n47p7bCOc0efZPAxZMO8R8hw6p3UAkW7UDsMbcBi7Xlh4tNFsflemXhfGQfRxBvsF4QG50LRa8Difi8dTV9zpTQ10I019SGFSqOd52ExD4L2Rh4tO2Xroab5Vwmww6hTC761GkQ4OexDPYhl5Gqs2UkBIhxyBglTPJI0f75EhhwKddJhlod05bqEEUUDBntHmkcNWExDYke10lEBHmwt0UJelsZGFvNCyc2_HsNkwtOXwG0dcFVXxso_jPZchRwl2SLMTGi_4biuN4vbTJwN7q22m7UW8IB7TjAVs2wcV0_Awb0j61iwLnti3UnUx0eo78B6Wb5jzNk7xXz8LZizI8yF5Fuj3zHmT716H9aNn8mIF7cvo2F_NuaF2XXV0w2K03pDuaa89HI3LIDUAhfuqLTG3QNL6RNu3KbigcCGco0l8VAwWy1gg_Vy1J3uJ4slb3ghlfSPb7LZ9NJDU7FHiLD8RPMRBwZQThYfpQun6AI2xsJbmPhzpIcOLejfgXUI-3iUdYejDqxs6XmhgDr_qIBkV4Sxeyl8RbJ8nKaETUi2IIyR7Dpyl0bFI9aAcGoyHZ_jZMYoevR_5lPMhK2ewOkr4KJ_s4MBkl3_y1hBl6bVPk4PxMF4vJ04PRZPOu65ieGs98zof0XFN3v0duxiYcTjSYcFLRV3LiIZsrRQpryjFVdyqxMFG49VAJ-9abokzZaI5TRqanp7xN8iN5u-LJmk-V-WTbIl1PiXTZUn2UIKwqZbfIqK4mC2LOxREgXysGE5Yn4LEEi25CTNKwubOJ2wLBqwFgfGoVmveUTYiv9vzR32oEODA_0b7D0Vi76n_pOR-F5JE3fed25kf-z4U4Y-LTZH5QUJaHpHSI8vBL-A83TJHRB24XBvD4Nh544cyHT9wOtGAR3j6DSN_8LHkbTbvMVDSb_-TuDB-fAJhSZfqJLF7fT2giag0ZhkPC2kT7DhdzT51N1Cw0NjrKfhZuycbjRhF91zM443r4twpKBdR_u1SsIuAiOinOZkdjW097RL7JtcGv91p1qp9z7FxzdzKfsml9hfd6n36G90qHMmfKPbX15_DpLiXQUeA8NBjzrT2rK_4uAiHqeRKd5VKK4h3lJIR7veIgz_RsV-iY2Or_IftecPHWlvFHUHarYMV1TZ9Qmv4mF3yUieDviUKbmKVQe17N0eOnzQ_hO3vAYP1h0OqkKhEHzw_fpl-UAqC4s1rvPAFLjFgftLheD83oLzIMINW38Mximim4LPaqAjWBSBjxD34k6HYETXsSvqiBF9d-htuoaGxnbGUW7haR-zV1tze9ehsDKW1sZiJLG_iK2U0SGgDoVa2IAN10WTxacd2J2Ee-zQjr5NTU-1HFvpq7YYlaYmbPVRYijNxl-Z0GfcS50xwlaFMgWCE6kC3J03TeJs2a2pkEmZCAut--rmguakRs3JNEmTDXDfWnDJxthkPyMZs1GN_cpoD610dNN9w0fkXNvgOoMusaNUWkd_Rik1Wj1iSodPVaGV7T51daxudFTwY2oepTsA5cqZl9NtsvguSH4NYsTqaa7vE_dMXGZins35GVyOZ2w8nqYTNj6rLlmWXcC8gNl0IyYwS7NielGI8nwyh7KYz2dn8pKl7DydjacsTS_Ox6NixseZ2GTzWXo-LsSMnKdQc6lGSu1q7EvPpHMtXM7n49n0TPEClAu_OGGsBs-LdhuOXEvCWPf1lmT54St4NxJ_hfCEbd_v7geMJ1m-551cndlLNCIp2q0j56mSzrveLC-9gsv-Zy3Pf91GiXT_g5Gz1qrLFwLafWoOihtr_g2lJ2wVMMBIRhh2l-w_AQAA__8v_9rt">