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

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

## DirectX

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

## SPIR-V

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

## 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 finding the largest signed integer 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>238</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 InterlockedMax_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 InterlockedMax(buffer[index], p1);
}
```
 ### Example 2
```hlsl
//dxc InterlockedMax_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, int64_t p2) {
int index = dispatchThreadID.x;
    return InterlockedMax(buffer[index], p1, p2);
}
```
 ### Example 3
```hlsl
//dxc InterlockedMax_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 InterlockedMax(buffer[index], p1);
}
```
 ### Example 4
```hlsl
//dxc InterlockedMax_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, int p2) {
int index = dispatchThreadID.x;
    return InterlockedMax(buffer[index], p1, p2);
}
```
## HLSL:

Performs a guaranteed atomic max.

## Syntax

``` syntax
void InterlockedMax(
  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 and 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 max 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 max of 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_zTMC2HDpmrHfsiDY8e7Adpt0QTdfQsocWzxQpECSSX2ffrDkJIsxU7SbNttcXdFEYvD4fz5zZAih-LOya0GuCCTSzJZnfHK58ZebLj9t9HqLDVifzGgZHJJyWRFr4tSQQHaUzIdXWsPVpnsHsQHviPTEc0U11uaVlJ5qQlbktHiMPa91PdfMYw-Sp8jX66cupPaW6mdzNwwJ9NRT-BCCOqg4DTLIbt3dGPsafneIH2JXL-_v3l_GRWtK515afSSK4VcUiPXDRQ8cEq9HWZleUppZgRsQb-m8KqQvqPvalfag57lbzX5NSUenHe1xAAUYWukEbZeGgG_gUYdhK1r_Bxh675FQ0TyWfBekI9Y1MKDsdcnhA_AWmPdSR1LC9wD9TmgcKn9ndjdHaPVxriG5rqN-UpayPxfQy9eFr366_r9x_IDL0uptyjSbF7U6A3F_vF0dAgIynhZ0XGshzFzuBbHfXc1MJElohw1KfVQHAWRsHXtLWHr14F05cObkLz5dP35ywn3rjUNXdfaeVuF-XADCjJvLCYmzXqajzUq8whW6m3AoOAlpdLXyfSSmWGmPaOXJAuSLFxotQ6Q6Wh4ChIUMvhCU57dgxYBZppxB69AHXQTtsasHRzWmOOpo-qkxv8sISyhTZQi7XxJMXHoxxLnK-20_-BFbN_kXIClH4wA1SXceL4Fh5Ra0ODwj77SPiYMOoLG01Hojxj9zrVQsDb2vUwDeTpMwi9hM8LmzbjWwQhpS0LEP5YLbwqZ3WAAJyvCZrn3pcNIsTVhawtb6bzdD-9za7RxQ2O3NcoDhNmVEMCttNxIEOMmAsPcF4qwpCefzVFuD3JwmZUlJknsopSMFp_AbowtQm5ujFLmEfPQeSgd5UEcV2ofXycW0ISQmVzvqfE52JqJjBY8y8A5cIEXE4ctbjJTAmELHIEKHEZTmYzXRgQLxgifMlxQn1tTbXMc-clITKF67BY85UHiRyu3UnNFv3BVoWjClkEKQymBD9n-gMeWg6Z7upFaoF9ohOJ2iwke3tgCZztswYbF7iCfjBbt-LAwsUVXI5JQa4JanTe2ntxPNfPs_rRXwzA8_LnNcZ61E5hcMTIbkfncId6V8lS6RviR9x0xhC0-R_7bfQS9qJynKQTkJpeELRpXfWT4ETl4HVUEWDKuuH3iKKquoW5RauxsM4Q7euTNkHaH-xzIaPGAEmgZQBWYJ-n-Se58peguiB-gMHaPg6WjnBahWQPY5POPQC7IvhtIMSBsPqxnbrL0PFVAkqvYyozaWlOVXQJ1fo8sK8LYoxQ-x4k1ZoRNCGMUjfs_8zczE7Y-wt7nwMWhZTsdJLn601hBl6bSPg4PxE5_fNed7ov56Z4bCJZr8UzvD6Biy_ZafcfxdHMSBoFnEuciviGRU9wT0JwrudUDBRtPH-KzNyVhLGpHhM-jpvJgj_guclkye1EyGS3-tmySLKHAXzZVniSXUhA23eJTVBQ7k2Vqe6kVyN0Vqcf8I0AgyZKT0SK3sInDCUuiAdeiZeya9ZpHhK35a-b-LGSbt8FPQbW7qHdxDfQ3wHrKsfpF9VP8irrv8GirvczcCRcjC21Zwtv1W_w9SPpKl39WxsWNzVcZeby09hZTJHTe_6P-hv4Wd7FL7oCwmcMNf-gMe5nIgUxXO16UCugYe8NJvS4KBTm4cRG7jD45dONJL9Qi6OCWKpneTe9mdAAabRmMp6n0A9yJOTr4WB_rPv95EzawlQVxWW02YcJJ7afv7jxJrmgaaBTfr3GjhPuzWTUK55RLlDG51FXhcwtcOMJmY9xmN3_muOEaLWBXGuvpg5GCbjSOl9onVEhXcp_lt2Hw9Spouflyt3pCR2G1SbQcx0MbqpbaU6kF7ChJVkfShrtoIKWUWvCV1U_QImwWvSOTyyAm7A6XUUXt3PmqC__pCLG3RGj8PxKjTov9IxFbRkVviFvylrix7xi3Xyxmv-KceveW2CT_5bGpn36JeVTHKdTFmzpVXYrCU_e24pZrDyDq-hIt-G7YL7Dttee7mtRIpq6hBsCOzA3eSE2WjCxG8e9nKkJdc3mi75Y-xCJF7DSVb-imrsTcRQa0qvG162Vr7SdueQEerGtP9kJhkuCDP7zf2SJas6Bksgywht9Vux8IzGGUaEfFUwPmf6gCxZ-6K4fgn9Sh5ka5EBacO9QXUKQ4achDU5_525bcPrVE6rLyEdOvsaABmUyWd0-swVB8kzkfQyGUq1hXajS9biE-q46RIbqf4-xocwG9lY5u6rsxKgw4qo1vphHva2iEFNzeu854gyf9ICDjmhqt9jQFWsZpAoIaHWY014LiqhCqY4JacKayGbjQ4XJuQTRlrAduJS5mLrhtgXIL1D8aWhrnZKqAVg7iHaDvehBR2kjrQjnyMQdNP8cC2WkFwZYhvdZRThZ2qctYZW5QKdv5rjuznJpNRKctGvcUNCsptbABCzoDQdN9yPFopIPMoN8ZaG6leWpug85zljbj_q61rfymzP2soeYB1yYuQByU5DzKF0LG9MQ1J2Zkbe1jLrOcPkqlMBcc-EZxm8LRHLNpVWEmHXQdkgrpmFP8gUtVC2-AwjdAIGEOPVoZjiF1vnZW1YM0R4UJKS6LEmXqfROxDfpO2Drl1kqwvaTHvP8gtSyqonfDc2oSYXCqEt-GoWr_9MYiji5wdLu8tbdLvdujb_wX5LWGtPdFg-_5ry_vcCdFJpc9VyanKtFb6fMqHWamIGz9QWbWOLPxKxPKz49SJwyjoUyKa1mkCnD33pQDZ7N6exTu5xIR9kxsLRIxHg-2lpe5zNygTemBKybDQuCOAhMll9scbD8WAa89uAN6veDEt-2bwx23YWZT63KHy6425l_AetzZnC_p75WKl4YrU3Cpw-NvYArwdh8an-SuvlZcmqKsPBzHtX08Res3uuRD7HaH9AnP7UPvMTZ2T55exK3ZEAFQrpx5eYMxuWxvg2nz7Yb7p7Jod0ih_p3xoAm7i9l04q3e8-EXnQTHZjfbhTNxkYh5MudncDE-Z-PxZD6bnZ_lF5MZm6XYmIgMkkl6nk7PWTpJkulmAixjZ_KCjdi70fl4Op5PZqPzIYyzEZuNgc-T6SYVCXk3goJLNVTqoRgauz2TzlVwMZ-P2bszxVNQLnyXxFgBnqfVNtTwloSx-sKfJIv2q4m6J36wcsTW3GY1HcaTZNHwTlZn9gKNGKTV1pF3IyWddwezvPQKLg4fPz37OQQKbJPzrLLq4oXY1h8nBL2lNf-CzBO2DhBgUCMKDxfsPwEAAP__g4FHKA">