<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/99127>99127</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            Implement the `InterlockedXor` 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 `InterlockedXor` clang builtin,
- [ ] Link `InterlockedXor` clang builtin with `hlsl_intrinsics.h`
- [ ] Add sema checks for `InterlockedXor` to `CheckHLSLBuiltinFunctionCall` in `SemaChecking.cpp`
- [ ] Add codegen for `InterlockedXor` to `EmitHLSLBuiltinExpr` in `CGBuiltin.cpp`
- [ ] Add codegen tests to `clang/test/CodeGenHLSL/builtins/InterlockedXor.hlsl`
- [ ] Add sema tests to `clang/test/SemaHLSL/BuiltIns/InterlockedXor-errors.hlsl`
- [ ] Create the `int_dx_InterlockedXor` intrinsic in `IntrinsicsDirectX.td`
- [ ] Create the `DXILOpMapping` of `int_dx_InterlockedXor` to  `160` in `DXIL.td`
- [ ] Create the  `InterlockedXor.ll` and `InterlockedXor_errors.ll` tests in `llvm/test/CodeGen/DirectX/`
- [ ] Create the `int_spv_InterlockedXor` intrinsic in `IntrinsicsSPIRV.td`
- [ ] In SPIRVInstructionSelector.cpp create the `InterlockedXor` lowering and map  it to `int_spv_InterlockedXor` in `SPIRVInstructionSelector::selectIntrinsic`.
- [ ] Create SPIR-V backend test case in `llvm/test/CodeGen/SPIRV/hlsl-intrinsics/InterlockedXor.ll`

## DirectX

| DXIL Opcode | DXIL OpName | Shader Model | Shader Stages |
| ----------- | ----------- | ------------ | ------------- |
| 160 | CreateHandleForLib | 6.3 | () |

## SPIR-V

# [OpAtomicXor](https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#OpAtomicXor):

## Description:
  
Perform the following steps atomically with respect to any other atomic
accesses within *Scope* to the same location:  
1) load through *Pointer* to get an *Original Value*,  
2) get a *New Value* by the bitwise exclusive OR of *Original Value* and
*Value*, and  
3) store the *New Value* back through *Pointer*.  
  
The instruction’s result is the *Original Value*.  
  
*Result Type* must be an [*integer type*](https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#Integer) scalar.  
  
The type of *Value* must be the same as *Result Type*. The type of the
value pointed to by *Pointer* must be the same as *Result Type*.  
  
*Memory* is a memory [*Scope*](https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#Scope_-id-).

<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>7</p></td>
<td class="tableblock halign-left valign-top"><p>242</p></td>
<td
class="tableblock halign-left valign-top"><p><em>&lt;id&gt;</em><br />
<em>Result Type</em></p></td>
<td class="tableblock halign-left valign-top"><p><a
href="#ResultId"><em>Result &lt;id&gt;</em></a></p></td>
<td
class="tableblock halign-left valign-top"><p><em>&lt;id&gt;</em><br />
<em>Pointer</em></p></td>
<td class="tableblock halign-left valign-top"><p><a
href="#Scope_-id-"><em>Scope &lt;id&gt;</em></a><br />
<em>Memory</em></p></td>
<td class="tableblock halign-left valign-top"><p><a
href="#Memory_Semantics_-id-"><em>Memory Semantics
&lt;id&gt;</em></a><br />
<em>Semantics</em></p></td>
<td
class="tableblock halign-left valign-top"><p><em>&lt;id&gt;</em><br />
<em>Value</em></p></td>
</tr>
</tbody>
</table>



## Test Case(s)

 
 ### Example 1
```hlsl
//dxc InterlockedXor_test.hlsl -T lib_6_8 -enable-16bit-types -O0

RWStructuredBuffer<int64_t> buffer : register(u0);
[numthreads(1, 1, 1)]
export void fn(uint3 dispatchThreadID : SV_DispatchThreadID, int64_t p1) {
int index = dispatchThreadID.x;
    return InterlockedXor(buffer[index], p1);
}
```
 ### Example 2
```hlsl
//dxc InterlockedXor_1_test.hlsl -T lib_6_8 -enable-16bit-types -O0

RWStructuredBuffer<int64_t> buffer : register(u0);
[numthreads(1, 1, 1)]
export void fn(uint3 dispatchThreadID : SV_DispatchThreadID, int64_t p1, uint64_t p2) {
int index = dispatchThreadID.x;
    return InterlockedXor(buffer[index], p1, p2);
}
```
 ### Example 3
```hlsl
//dxc InterlockedXor_2_test.hlsl -T lib_6_8 -enable-16bit-types -O0

RWStructuredBuffer<int> buffer : register(u0);
[numthreads(1, 1, 1)]
export void fn(uint3 dispatchThreadID : SV_DispatchThreadID, int p1) {
int index = dispatchThreadID.x;
    return InterlockedXor(buffer[index], p1);
}
```
 ### Example 4
```hlsl
//dxc InterlockedXor_3_test.hlsl -T lib_6_8 -enable-16bit-types -O0

RWStructuredBuffer<int> buffer : register(u0);
[numthreads(1, 1, 1)]
export void fn(uint3 dispatchThreadID : SV_DispatchThreadID, int p1, uint p2) {
int index = dispatchThreadID.x;
    return InterlockedXor(buffer[index], p1, p2);
}
```
## HLSL:

Performs a guaranteed atomic xor.

## Syntax

``` syntax
void InterlockedXor(
  in  R dest,
  in  T value,
  out T original_value
);
```

## Parameters

<dl> <dt>

*dest* \[in\]
</dt> <dd>

Type: **R**

The destination address.

</dd> <dt>

*value* \[in\]
</dt> <dd>

Type: **T**

The input value.

</dd> <dt>

*original\_value* \[out\]
</dt> <dd>

Type: **T**

Optional. The original input value.

</dd> </dl>

## Return value

This function does not return a value.

## Remarks

This operation can only be performed on int or uint typed resources and shared memory variables. There are two possible uses for this function. The first is when R is a shared memory variable type. In this case, the function performs an atomic XOR of value to the shared memory register referenced by dest. The second scenario is when R is a resource variable type. In this scenario, the function performs an atomic XORof value to the resource location referenced by dest. The overloaded function has an additional output variable which will be set to the original value of dest. This overloaded operation is only available when R is readable and writable.

Interlocked operations do not imply any memory fence/barrier.

### Minimum Shader Model

This function is supported in the following shader models.



| Shader Model                                                                | Supported |
|-----------------------------------------------------------------------------|-----------|
| [Shader Model 5](https://github.com/MicrosoftDocs/win32/blob/docs/desktop-src//direct3dhlsl/d3d11-graphics-reference-sm5.md) and higher shader models | yes       |



 

This function is supported in the following types of shaders:



| Vertex | Hull | Domain | Geometry | Pixel | Compute |
|--------|------|--------|----------|-------|---------|
|  x     |  x   | x      |  x       | x     | x       |



 

## See also

<dl> <dt>

[Intrinsic Functions](https://github.com/MicrosoftDocs/win32/blob/docs/desktop-src//direct3dhlsl/dx-graphics-hlsl-intrinsic-functions.md)
</dt> <dt>

[Shader Model 5](https://github.com/MicrosoftDocs/win32/blob/docs/desktop-src//direct3dhlsl/d3d11-graphics-reference-sm5.md)
</dt> </dl>
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzsWl9v2zgS_zTMC2HDpmInfsiDY8e7AdpNkQTdvgW0OLZ4oUiBpBz7Pv1hSEmWYuffdrst7q4oYnE4nD-_GVLkUNw5udYAF2R0SUbzE176zNiLFbf_NlqdLI3YXfQoGV1SMprT67xQkIP2lIwH19qDVSZ9BPHNWDIe0FRxvabLUiovNWEzMpjux36S-vEdw-iT9BnyZcqpB6m9ldrJ1PUzMh50BE6FoA5yTtMM0kdHV8Yel-8N0mfI9funu0-XUdGi1KmXRs-4UsglNXLdQc4Dp9TrfloUx5SmRsAa9FsKr3LpW_qutoXd65n9VpHfUuLBeVdJDEARtkAaYYuZEfAbaNRB2KLCzxG26FrURyRfBO8V-YhFJTwYe31EeA-sNdYd1TGzwD1QnwEKl9o_iO3DIVpNjCtorpuYz6WF1H_re_G66Pm36083xWdeFFKvUaRZvarRG4r9w_FgHxCU8bqiw1j3Y-ZwLQ77HipgIktEOWpSapMfBJGwReUtYYu3gXTF5kNI3n25vv16xL1rTUPXtXbelmE-3IGC1BuLiUnTjuZDjco8gZV6HTDIeUGp9FUyvWZmmGkv6CXJlCRTF1qNA2Q86B-DBIX0vtIlTx9BiwAzTbmDN6AOuglbYNb29mvM4dRRVVLjf5YQltA6SpF2NqOYOPSmwPlKW-0_eB7bdxkXYOlnI0C1CXeer8EhpRLU2_-jb7QPCb2WoOF4EPojRr9zLRQsjP0kl4E87ifhl7Bzwib1uMbBCGlDQsRviqk3uUwxfqM5YeeZ94XDQLEFYQsLa-m83fUfM2u0cX1j1xXIPUTZFRCwLbVcSRDDOgD9zOeKsKQtnk1QbAdwcKmVBaZI7KKUDKZfwK6MzUNmroxS5gmz0HkoHOVBGldqF18mFtCCkJdc76jxGdiKiQymPE3BOXCBF9OGTe9SUwBhUxyBChzGUpmUV0YEC4YInjJcUJ9ZU64zHPnFSEygauwaPOVB4o2Va6m5ol-5KlE0YbMghaGUwIdsf8BTw0GXu6B8Kf2TdEBhm6rSyQ3Qm9uwwB2RitMwIDdt68G5iboS1OW8sdWEfq6Pp4_HfemH4eHPfYZzq5m05IqR8wGZTByiXCpPpauFH1jXEkPY9Dby3-8i1HnpPF1CwGt0SdgUla_BUh8ZfkTiXUcVAZaUK26fOYqqK6gblGo7m7zgjh5406ft4T4DMphuUAItAqgCs2O5e5Yx7xTdBvEz5MbucLB0lNM8NCsA6yz-EcgF2Q89KXqETfrVfE1mni8VkOQqtlKj1taURZtAnd8hy5ww9iSFz3A6DRlhI8IYReP-z_zdzIQtDrD3GXCxb9lWB0mu_jRW0JkptY_DA7HVH99vx_tifrqXBoLlWrzQ-wOo2LKdVtdxPNEchUHgOcS5iG9I5CXuA2jGlVzrnoKVp5v47E1BGIvaEeGzqKnY2yP-FrnslL0qmQymf1k2SWaQ4y8bK0-SSykIG6_xKSqKnclsaTupFcjtFanD_CNAIMmMk8E0s7CKwwlLogHXomFsm_WWR4Qt-Fvm_ixk67fBT0G1vai3cQ30D8B6zLHqRfVT_Iq6H_A4q71M3REXIwttWMLb9Xv83Ut6p8s_K-PixuZdRh4urZ3FFAmt9_-gu42_x6PZjDsg7NzhNj90hr1M5ECmqy3PCwV0iL3hdF4VgoIc3LiIbUqfHbTxdBfqD7R3T5VcPowfzmkPNNrSG46X0vdwJ-Zo76Y6yt3-eRc2sKUFcVmuVmHCSe3Hpw-eJFd0GWgU369xo4T7s_NyEE4nlyhjdKnL3GcWuHCEnQ9xm13_meCGazCFbWGspxsjBV1pHC-1T6iQruA-ze7D4Ot50HL39WH-jI7CKpNoMYwHNVQttadSC9hSkswPpPW30UBKKbXgS6ufoUXYefSOjC6DmLA7nEUVlXNn8zb8xyPEPhKh4f9IjGa0bJrsHwnZLCr6QOCSjwSO_Y2B-8WC9itOqtOPxCb5L49NnEy_yESqAhWq4XV9qipB4bl7XXLLtQcQVV2Jbo3td8tqO-35tiLVkqmrqQGxA3ODN1KTGSPTQfx7S0WoZs6O9N3TTSxTxE5T-ppuqlrMQ2RAq2pf21421n7hlufgwbrmbC8UZgk--P0bnk2jNVNKRrMAa_idNzuCwBxGiWZUPDfgBAh1oPhTdWUQ_JM61NooF8KCc_sKA4oURw3Z1BWav2zJ_XNLpC5KHzF9jwU1yGQ0e3hmDYbiu8y5CQVQrmJlqdb0toX4rFpGhujextnR5AJ6Kx1dVTdiVBhwVBtfTyPe1VALybl9dK3xBs_6QUDKNTVa7egSaBGnCQhqdJjcxsaZjWuToBacKW0KLpQpXcYtiLqOteFW4mLmgtcWKLdA_ZOhhXFOLhXQ0kG8-PNtByJIK2ldqEc-ZaDpbayQHVcQbOnTax3lpGGbOovF5RqUopnuup7k32IlNlb26lpxR0G9klILK7CgUxB0uQspHo10kBr0OwXNrTTPza3RecnSetw7rX1ubCO-Lm6_aKfZ4MrEBYi9joxH8ULImJy44sR8rIx9ymSa0SepFGaCA18rbhI4mmNWjSrMo72ufUohHTOKb7hUlfAaJ1z_AwlT6MnKcAypsrW1pu6lOSpMSHCZFyhT7-qArdB3whZLbq2E7hqOWf9ZapmXeedW59gUwtiUBb4MQVCpn99TxNE5jm4Wt-ZGqXNj9J3_grzGkOaOqPd3_uvK299DkdFlx5XRsUr0WvqsXPZTkxO2-CxTa5xZ-bkJ5ecnqROG0VBmiStZpApwj94UPWfTancU7uQSEbZMbCESMRz21pYXmUxdr0npnstH_VzgfgITJZPrDGw3FgGvHbg9ep3gxHfth8Mdd2FmVely-yuuJuZfwXrc15zN6O-liheFc5NzqcPjb2By8HYXGl_ktrpKnJm8KD0cxrV5PEbrNtrkfezotkmf8IgPW9ql0Q69xfEabvV2CIBy5czr24vRZXMDTOvvNdw_lUXbfQp174l7ddhdzKYj7_SOD7_oJDg0u94snIiLREySCT-Bi-EZGw5Hk8mAnWQXMODng5QPE3G6ArHi43QyOhsmbDRJGGenwxN5wQbsdHA2HA8no3PG-pNJsuLJIBEMBD-Fc3I6gJxL1Vdqk_eNXZ9I50q4mEyG7OxE8SUoF75FYiwHz5flOtTwZoSx6pKfJNPmS4mqJ36kcsBW32bVHcaTZFrzjuYn9gKN6C3LtSOnAyWdd3uzvPQKLvYfPL34CQQKbJLzpLTq4pXYVh8kBL2FNf-C1BO2CBBgUCMKmwv2nwAAAP__k55Emw">