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

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

## DirectX

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

## SPIR-V

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

## 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* from *Value* only if *Original Value* equals
*Comparator*, and  
3) store the *New Value* back through *Pointer* only if *Original Value*
equaled *Comparator*.  
  
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.  
  
Use *Equal* for the memory semantics of this instruction when *Value*
and *Original Value* compare equal.  
  
Use *Unequal* for the memory semantics of this instruction when *Value*
and *Original Value* compare unequal. *Unequal* must not be set to
**Release** or **Acquire and Release**. In addition, *Unequal* cannot be
set to a stronger memory-order then *Equal*.  
  
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*. This
type must also match the type of *Comparator*.  
  
*Memory* is a memory [*Scope*](https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#Scope_-id-).

<table style="width:100%;">
<colgroup>
<col style="width: 10%" />
<col style="width: 10%" />
<col style="width: 10%" />
<col style="width: 10%" />
<col style="width: 10%" />
<col style="width: 10%" />
<col style="width: 10%" />
<col style="width: 10%" />
<col style="width: 10%" />
<col style="width: 10%" />
</colgroup>
<thead>
<tr>
<th>Word Count</th>
<th>Opcode</th>
<th>Results</th>
<th>Operands</th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p>9</p></td>
<td class="tableblock halign-left valign-top"><p>230</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>Equal</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>Unequal</em></p></td>
<td
class="tableblock halign-left valign-top"><p><em>&lt;id&gt;</em><br />
<em>Value</em></p></td>
<td
class="tableblock halign-left valign-top"><p><em>&lt;id&gt;</em><br />
<em>Comparator</em></p></td>
</tr>
</tbody>
</table>



## Test Case(s)

 
 ### Example 1
```hlsl
//dxc InterlockedCompareExchange_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, uint64_t p3) {
int index = dispatchThreadID.x;
    return InterlockedCompareExchange(buffer[index], p1, p2, p3);
}
```
 ### Example 2
```hlsl
//dxc InterlockedCompareExchange_1_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, uint p3) {
int index = dispatchThreadID.x;
    return InterlockedCompareExchange(buffer[index], p1, p2, p3);
}
```
## HLSL:

Atomically compares the destination with the comparison value. If they are identical, the destination is overwritten with the input value. The original value is set to the destination's original value.

## Syntax

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

## Parameters

<dl> <dt>

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

Type: **R**

The destination address.

</dd> <dt>

*compare\_value* \[in\]
</dt> <dd>

Type: **T**

The comparison value.

</dd> <dt>

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

Type: **T**

The input value.

</dd> <dt>

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

Type: **T**

The original value.

</dd> </dl>

## Return value

This function does not return a value.

## Remarks

Atomically compares the value referenced by *dest* with *compare\_value*, stores *value* in the location referenced by *dest* if the values match, returns the original value of *dest* in *original\_value*. 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 the operation on the shared memory register referenced by *dest*. The second scenario is when R is a resource variable type. In this scenario, the function performs the operation on the resource location referenced by *dest*. This operation is only available when R is readable and writable.

Interlocked operations do not imply any memory fence/barrier.

> [!Note]  
> If you call **InterlockedCompareExchange** in a [**for**](https://github.com/MicrosoftDocs/win32/blob/docs/desktop-src//direct3dhlsl/dx-graphics-hlsl-for.md) or [**while**](https://github.com/MicrosoftDocs/win32/blob/docs/desktop-src//direct3dhlsl/dx-graphics-hlsl-while.md) compute shader loop, to properly compile, you must use the **\[allow\_uav\_condition\]** attribute on that loop.

 

### 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/eJzsWt9u27jSfxrmhrAhU7ETX-RCceLdAO22SLrdvQtocWTxK0VqSSqJv6c_GFKSZcdx0u12W-Ccooglcjjz4_wjORR3Tq41wAWZXpLp1QlvfGnsRcHt_xutTlZGbC5GlEwvKZle0ZuqVlCB9pTMkhvtwSqTfwGxMFXNLVw_5SXXayCzhOaK6zVdNVJ5qQlbkCTb8nkn9ZevZEEfpS9xTKmcupfaW6mdzN24JLNkh3kmBHVQcZqXkH9xtDD2dVneIM0CR_z67u7dZRS6bHTupdELrhRSSY1Ud1DxQCn1epzX9SEAuRGwBv01wq8r6Qeyr59qu5W5-KVtfk2gB-ddyzEokLAlthG2XBgBv4BGGYQtW706wpYvoxujtl9U8BFZqKNWUAB-84qgEVhrrDsob2GBe6C-BBQktb8XT_fHNdr7R6u-m95frqSF3P859uK4mKs_b959qN_zupZ6jSxN8Wbp3lCkncySrQGR33Ghx_1kHD2Qa3Gc7r5VZCSPFooIlHqonjkDYctWI4QtX1e8qx_-tubvPt7cfj6gghtNQ9eNdt42Id7uQEHujUVnp_kOiuPSlXkEK_U66KniNaXStw76Vvghwl_AQ9KMpJkLb_3EyCwZH1IbMhl9piuefwEtgilozh28Yo4gm7AlRsJom-eOh6lqgwb_s5SwlHZWjW1nC4oOSD_UmCfo4P03XsX3u5ILsPS9EaCGDXeer8FhS8totP1HX3l_3jAaMJrMktAf9fUr10LB0th3chWaZ-M0_BJ2Tti8G9dPMKq3b0Ltf6gzbyqZ79t1ekXYeel97dCAbEnY0sJaOm834y-lNdq4sbHrVvkj1L6rIei80bKQICadYcalrxRh6Uui2BxF7BgCXG5ljW4UuyglSfYRbGFsFby6MEqZR_Ra56F2lAfOXKlNXPQsIJrgx1xvqPEl2JaIJBnPc3AOXKBF12LZXW5qICzDESjAoY2VyXkLIiCYoFKV4YL60ppmXeLIj0aik7Vj1-ApDxw_WLmWmiv6masGWRO2CFwYcgl0SPYbPPYUtLCmwsa-wWi1obI4yI_CXw1XLqgti0rlGHBREkYzSktRmvPGtulgTyKG2guzOSabJFmQDoLuCx8HseHPpxIjt08J5JqR84TM5w7t0yhPpetAPZMwYENYdhvpP22ikarGebqCoOnpJWEZgl6DpT4SfA_3vYkigjpzrrgdIPzdhUlco0qCHY0NE6ugMnYTVn7tZe5wRfSldEOt0McS9NDo6KBaHDZ5HmMnmv45gN81_GsQGt2C2JUbTKNNMI8DjMBowWBEBdzFUMgo7vLCU5b_1UgLwWN3SMa4znEhZHAettiTlHMd5ZAki5Iop85bo9ET4rxHxmJC9u38OgPt-Sh6TdisDCKvc7E-GXBHnznimA6H-xKhPCAHWoc4EghqtdkLrDezlhjcgXsYwpUztOI-L8PQAeqXApCw7H3QA4qVjvLOHWLUdEnve4RL4H0_kmJE2Hzcpvd04flKAXV-o4CkV4SxRyl8SdJskiSETUl6SRgj6XWkzo1aW9PUw4ZDg-kkDGaMIvj_Ef_ExIQtn1nVl8DF9s0OOkh6_Yexgi5Mo30cHhoH_XGDdrgvxpR7aSBYrsULvT-4Fd_sztuuklZGbA6qTNBcceeiLUK4rXADTEuu5FqPFBSePsRnb-o22tIFWmMeJdVbPOIf4cvS5ChnkmR_mzdJF1DhL5spT9JLKQibrfEpCoqd6WJld9wwNA8z7g7x91ACSRecJFlpoYjDCUsjgBvREw5hvTYjwpb8Nbg_SrPdavdDtDpceoZ6De1fodZDE2uX0x8yryj7_q7byh2YYiShPUnYA3zLfOOO6b9mut328o0T_lHhFXepPznIwab0TUifr3g7axw2IPa2IdktGXwC5-kiHB3OHWHz2Bk2wpECia6feFUroBPsDZXGtjge-OCuVzzl9Eih0IPzod5KR5-okqv72f05HYFGXKPJbCX9CHfljo4-tKWl2z_uwimrsSAum6IIOVFqPzu99yS9pqvQRnG7FHfceEQ4b5JQFblEHtNL3VS-tMCFI-x8ggeh7s8cd-5JBk-1sZ4-GClooXG81D6lQroaTwufwuCbqyDl7vP91V47Mmsh0TqwbvpXtvuaxrISApPaU6kFPFGSXj2TNX6K8Cml1IJvrD6iV8LOox7I9DKwDAeSRQsmYgiiW5WcXQ0NeNjG7O_aePIPWvkns_DAugPL_rRWbS0a7kS6CmG2LfS1hYhYQhLgvNQ8VjOkjyfkSCGd0TScysf0JpzSN5RboFIALhpcIZB9HtJR8wD20UrvYcBS6rrxHTc8_JuuQBLP_dK1VY99joSduT3i8W5xdqM9f2qbOi1Q17UG0x9VdrCL1GTBSJbEv7cBQbxK3O_71Cnw_iHWPA4T7XSaxnft3VTa0TiNzpBDE_bT-8gtr8CDdX0tQCiMD3zw26TOsgg5o2S6CJ4Tfq_6RSAQh1GiHxV38FlbULqNP23XnmG5EBac21YkkKU4CKTVD5kuOhV9A6hP-6CeOecbEH0HGEOHfgOCzuwHlILO8c1wDkfILiJ8VgNQwb9uYzrqvRHZSUeL9jqaCgMu1CXbvMUPxeAtVNx-ccdTTQx0CwVY0DmItsDXuW28dD_oPZhoQik-1Pt69Ukd-Ha3DS-zlsUWgIuVQGQZZxTB7aWjWB7sx4ci6CETxmojNTXYiCHnOl4ArIDW8eIFBDW6tRuubXtl3GbbhqujoBacaWwOLlR2XcktiK7--MCtxOXUhSRqISRk_2hobZyTKwW0ceDaIvbAjDHnFtK6cHkQ6ta3sbJ5WEDAEgrJgU8edogx3feu0c6vVWCvAhPNssu3W8JfNFJE6CA3OOkcNLfS7GPtVPMSzG7cV0Lt2b7qSs_sjS9obv7ApQqItnhx7Q9NaEdcEfGlDZzBirTl5qgwIdZkVSNPvenUVyAWwpYrbq0E28f3daxIT34zHsj0Khav02tcrzemoRiFrZsdWwKz1sl5W98mLCvaC7GDNe619GWzGuemImz5XubWOFP4KxMK249SpwyhKrPCjBNbBbgv3tQjZ_N2NxkujVMRtpi4uRytLa9LmbtRuI4ujB1XAjdYGCkdrMdSKvixwAKEFhrmqsYHXxdgqTJ4DFzgLqa2aNU2BQbMi2CRcCHRuP5SMUwEVwGulHnE1NLwB_zBOIgXOHFtiEbi3lu5QpHBdbkPMjt3iBuQQWLG3Pxealk11c6l-6FEj-HT1LhdBtGl1sF1cRxd4eh-E9Bf-O9c6H_jv8CvB9Jf4Y_-yX-7_LafCZDp5c5Upv-Wk6ViMtn6WZ99Rq6atq6GOaSU6xLsri2CvjbgttrbMc7AJb7G3PGcZopWltt-adDb_DNYj8edswX9tVHxO44rU3FcLM8W9BcwFXi7CS8f5VP7pceijZhndu0fD7Xtvgybt7Z72rpPeO4fdh7jy9Pe01G9decMgHCTeHwbPr3sP9ah3Sd97kelqv6TnlFndhe96cBOc2cOP2kQPIfdbWlPxEUq5umcn8DF5IxNJrMkOT09KS_ysxlAMTktzler_IydpfMCxFk-ywFOJ3lenMgLlrDT5GwyYwmOGc9ZUczz82KVpDMxPyvIaQIVl2qs1EM1NnZ9Ip1r4GI-n6TJieIrUC580spYBZ6vmnUowy4IY-33WCTN-g_f2p74veIzsu6WuOswnqRZRzu9OrEXCGK0ataOnCZKOu-2sLz0Ci62382-6Ss2ZN476klj1cURO7ffkQUMtTX_B7knbBnUgQaOGnm4YP8JAAD__4flTwQ">