Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Interlocked for small types. #92974

Merged
merged 67 commits into from
Jan 25, 2024

Conversation

MichalPetryka
Copy link
Contributor

Implements Interlocked.CompareExchange/Exchange for byte/sbyte/short/ushort.

Uses an intrinsic on CoreCLR x64 and ARM64 and fallbacks for other platforms.

Fixes #64658.

Implements Interlocked.CompareExchange/Exchange for
byte/sbyte/short/ushort.

Uses an intrinsic on CoreCLR x64 and ARM64 and fallbacks
for other platforms.

Fixes dotnet#64658.
@dotnet-issue-labeler
Copy link

Note regarding the new-api-needs-documentation label:

This serves as a reminder for when your PR is modifying a ref *.cs file and adding/modifying public APIs, please make sure the API implementation in the src *.cs file is documented with triple slash comments, so the PR reviewers can sign off that change.

@ghost ghost added the community-contribution Indicates that the PR has been added by a community member label Oct 3, 2023
@ghost
Copy link

ghost commented Oct 3, 2023

Tagging subscribers to this area: @mangod9
See info in area-owners.md if you want to be subscribed.

Issue Details

Implements Interlocked.CompareExchange/Exchange for byte/sbyte/short/ushort.

Uses an intrinsic on CoreCLR x64 and ARM64 and fallbacks for other platforms.

Fixes #64658.

Author: MichalPetryka
Assignees: -
Labels:

area-System.Threading, new-api-needs-documentation

Milestone: -

@MichalPetryka
Copy link
Contributor Author

MichalPetryka commented Jan 24, 2024

@jkotas I've realised there's a potential issue with atomics as FCalls: some compilers might implement them with locking on a mutex which AFAIR is not okay inside of an FCall. Checking with CLang on godbolt makes it seem to be the case on arm32.

These are results for stdatomic.h header. We do not use stdatomic.h. We use the compiler intrinsics directly. You may want to step through the disassembly on arm32 to see what the compiler intrinsics end up doing.

I've checked that earlier, it calls into a __atomic_exchange_1/2/4/8 helper (which means it probably implicitly links libatomic there). It does a similar thing for arm 8.0, just with __aarch64_swp1_acq_rel (which is fine according to that define).

Additionally, on arm32 it gives such warning:

<source>:5:12: warning: large atomic operation may incur significant performance penalty; the access size (1 bytes) exceeds the max lock-free size (0  bytes) [-Watomic-alignment]
    5 |     return __atomic_exchange_n(ptr, val, __ATOMIC_ACQ_REL);
<source>:9:12: warning: large atomic operation may incur significant performance penalty; the access size (2 bytes) exceeds the max lock-free size (0  bytes) [-Watomic-alignment]
    9 |     return __atomic_exchange_n(ptr, val, __ATOMIC_ACQ_REL);
<source>:13:12: warning: large atomic operation may incur significant performance penalty; the access size (4 bytes) exceeds the max lock-free size (0  bytes) [-Watomic-alignment]
   13 |     return __atomic_exchange_n(ptr, val, __ATOMIC_ACQ_REL);
<source>:17:12: warning: large atomic operation may incur significant performance penalty; the access size (8 bytes) exceeds the max lock-free size (0  bytes) [-Watomic-alignment]
   17 |     return __atomic_exchange_n(ptr, val, __ATOMIC_ACQ_REL);

@jkotas
Copy link
Member

jkotas commented Jan 24, 2024

It is a problem with __atomic_exchange_n that is used for InterlockedExchange. __atomic_exchange_n is also the one that caused troubles on Linux x86 before.

Other operations are implemented using __sync_val_... intrinsics. Do __sync_val_... intrinsics have the same problem?

If __sync_val_... intrinsics are fine:

  • Use __sync_swap to implement InterlockedExchange when compiling using LLVM. We do that here already:
    #ifdef __clang__
    return __sync_swap(pDst, iValue);
    #else
    return __atomic_exchange_n(pDst, iValue, __ATOMIC_ACQ_REL);
    #endif
  • Implement InterlockedExchange using __sync_val_compare_and_swap when not compiling using LLVM. Similar to what I have done to fix the Linux x86 break:
    #if defined(HOST_X86)
    // 64-bit __atomic_exchange_n is not expanded as a compiler intrinsic on Linux x86.
    // Use inline implementation instead.
    inline LONGLONG InterlockedExchange64(LONGLONG volatile * Target, LONGLONG Value)
    {
    LONGLONG Old;
    do {
    Old = *Target;
    } while (__sync_val_compare_and_swap(Target, Old, Value) != Old);
    return Old;
    }
    #else

@MichalPetryka
Copy link
Contributor Author

I've opened a new issue to track this as this PR doesn't introduce the issue: #97452.

@MichalPetryka
Copy link
Contributor Author

MichalPetryka commented Jan 24, 2024

ARM32 failure seems like an unrelated JIT bug with longs.
Turns out a small bug in the helpers somehow trashed the stack.

@jkotas
Copy link
Member

jkotas commented Jan 24, 2024

I've opened a new issue to track this as this PR doesn't introduce the issue: #97452.

It does not introduce it, but it makes the problem worse. Could you please replace the new uses of __atomic_exchange_n with what I have suggested? It should address the issue. (Bonus points for fixing the existing uses too.)

@MichalPetryka
Copy link
Contributor Author

I've opened a new issue to track this as this PR doesn't introduce the issue: #97452.

It does not introduce it, but it makes the problem worse. Could you please replace the new uses of __atomic_exchange_n with what I have suggested? It should address the issue. (Bonus points for fixing the existing uses too.)

As I've noted in that issue, those other APIs also use helper calls so I'd assume they have the same issue.

@ryujit-bot
Copy link

Diff results for #92974

Throughput diffs

Throughput diffs for linux/x64 ran on windows/x64

Overall (+0.00% to +0.02%)
Collection PDIFF
benchmarks.run.linux.x64.checked.mch +0.01%
benchmarks.run_pgo.linux.x64.checked.mch +0.01%
benchmarks.run_tiered.linux.x64.checked.mch +0.02%
coreclr_tests.run.linux.x64.checked.mch +0.01%
libraries.pmi.linux.x64.checked.mch +0.01%
libraries_tests.run.linux.x64.Release.mch +0.01%
libraries_tests_no_tiered_compilation.run.linux.x64.Release.mch +0.01%
realworld.run.linux.x64.checked.mch +0.01%
MinOpts (+0.01% to +0.03%)
Collection PDIFF
benchmarks.run.linux.x64.checked.mch +0.03%
benchmarks.run_pgo.linux.x64.checked.mch +0.03%
benchmarks.run_tiered.linux.x64.checked.mch +0.03%
coreclr_tests.run.linux.x64.checked.mch +0.02%
libraries.crossgen2.linux.x64.checked.mch +0.03%
libraries.pmi.linux.x64.checked.mch +0.01%
libraries_tests.run.linux.x64.Release.mch +0.03%
libraries_tests_no_tiered_compilation.run.linux.x64.Release.mch +0.03%
realworld.run.linux.x64.checked.mch +0.02%
smoke_tests.nativeaot.linux.x64.checked.mch +0.01%
FullOpts (+0.00% to +0.01%)
Collection PDIFF
benchmarks.run.linux.x64.checked.mch +0.01%
benchmarks.run_pgo.linux.x64.checked.mch +0.01%
benchmarks.run_tiered.linux.x64.checked.mch +0.01%
libraries.pmi.linux.x64.checked.mch +0.01%
libraries_tests.run.linux.x64.Release.mch +0.01%
realworld.run.linux.x64.checked.mch +0.01%

Throughput diffs for windows/x64 ran on windows/x64

Overall (-0.01% to -0.00%)
Collection PDIFF
coreclr_tests.run.windows.x64.checked.mch -0.01%
libraries.crossgen2.windows.x64.checked.mch -0.01%
libraries_tests.run.windows.x64.Release.mch -0.01%
smoke_tests.nativeaot.windows.x64.checked.mch -0.01%
MinOpts (-0.02% to +0.00%)
Collection PDIFF
aspnet.run.windows.x64.checked.mch -0.01%
benchmarks.run_pgo.windows.x64.checked.mch -0.01%
benchmarks.run_tiered.windows.x64.checked.mch -0.01%
coreclr_tests.run.windows.x64.checked.mch -0.01%
libraries.pmi.windows.x64.checked.mch -0.02%
libraries_tests.run.windows.x64.Release.mch -0.01%
realworld.run.windows.x64.checked.mch -0.01%
smoke_tests.nativeaot.windows.x64.checked.mch -0.02%
FullOpts (-0.01% to -0.00%)
Collection PDIFF
libraries.crossgen2.windows.x64.checked.mch -0.01%
smoke_tests.nativeaot.windows.x64.checked.mch -0.01%

Details here


Throughput diffs for linux/x64 ran on linux/x64

Overall (-0.03% to -0.01%)
Collection PDIFF
realworld.run.linux.x64.checked.mch -0.01%
benchmarks.run.linux.x64.checked.mch -0.01%
smoke_tests.nativeaot.linux.x64.checked.mch -0.02%
libraries.pmi.linux.x64.checked.mch -0.01%
benchmarks.run_tiered.linux.x64.checked.mch -0.03%
benchmarks.run_pgo.linux.x64.checked.mch -0.02%
libraries_tests_no_tiered_compilation.run.linux.x64.Release.mch -0.01%
coreclr_tests.run.linux.x64.checked.mch -0.03%
libraries.crossgen2.linux.x64.checked.mch -0.02%
libraries_tests.run.linux.x64.Release.mch -0.02%
MinOpts (-0.07% to -0.04%)
Collection PDIFF
realworld.run.linux.x64.checked.mch -0.05%
benchmarks.run.linux.x64.checked.mch -0.06%
smoke_tests.nativeaot.linux.x64.checked.mch -0.05%
libraries.pmi.linux.x64.checked.mch -0.04%
benchmarks.run_tiered.linux.x64.checked.mch -0.06%
benchmarks.run_pgo.linux.x64.checked.mch -0.06%
libraries_tests_no_tiered_compilation.run.linux.x64.Release.mch -0.05%
coreclr_tests.run.linux.x64.checked.mch -0.04%
libraries.crossgen2.linux.x64.checked.mch -0.07%
libraries_tests.run.linux.x64.Release.mch -0.06%
FullOpts (-0.02% to -0.01%)
Collection PDIFF
realworld.run.linux.x64.checked.mch -0.01%
benchmarks.run.linux.x64.checked.mch -0.01%
smoke_tests.nativeaot.linux.x64.checked.mch -0.02%
libraries.pmi.linux.x64.checked.mch -0.01%
benchmarks.run_tiered.linux.x64.checked.mch -0.01%
benchmarks.run_pgo.linux.x64.checked.mch -0.01%
libraries_tests_no_tiered_compilation.run.linux.x64.Release.mch -0.01%
coreclr_tests.run.linux.x64.checked.mch -0.01%
libraries.crossgen2.linux.x64.checked.mch -0.02%
libraries_tests.run.linux.x64.Release.mch -0.01%

Details here


Throughput diffs for windows/x86 ran on windows/x86

Overall (+0.00% to +0.01%)
Collection PDIFF
benchmarks.run.windows.x86.checked.mch +0.01%
benchmarks.run_tiered.windows.x86.checked.mch +0.01%
coreclr_tests.run.windows.x86.checked.mch +0.01%
libraries.crossgen2.windows.x86.checked.mch +0.01%
libraries.pmi.windows.x86.checked.mch +0.01%
libraries_tests.run.windows.x86.Release.mch +0.01%
libraries_tests_no_tiered_compilation.run.windows.x86.Release.mch +0.01%
realworld.run.windows.x86.checked.mch +0.01%
MinOpts (+0.01% to +0.02%)
Collection PDIFF
benchmarks.run.windows.x86.checked.mch +0.01%
benchmarks.run_pgo.windows.x86.checked.mch +0.01%
benchmarks.run_tiered.windows.x86.checked.mch +0.01%
coreclr_tests.run.windows.x86.checked.mch +0.01%
libraries.crossgen2.windows.x86.checked.mch +0.01%
libraries.pmi.windows.x86.checked.mch +0.02%
libraries_tests.run.windows.x86.Release.mch +0.01%
libraries_tests_no_tiered_compilation.run.windows.x86.Release.mch +0.01%
realworld.run.windows.x86.checked.mch +0.01%
FullOpts (+0.00% to +0.01%)
Collection PDIFF
benchmarks.run.windows.x86.checked.mch +0.01%
libraries.crossgen2.windows.x86.checked.mch +0.01%
libraries.pmi.windows.x86.checked.mch +0.01%
libraries_tests_no_tiered_compilation.run.windows.x86.Release.mch +0.01%
realworld.run.windows.x86.checked.mch +0.01%

Details here


@MichalPetryka
Copy link
Contributor Author

@MihuBot

@ryujit-bot
Copy link

Diff results for #92974

Throughput diffs

Throughput diffs for linux/x64 ran on windows/x64

Overall (+0.00% to +0.01%)
Collection PDIFF
realworld.run.linux.x64.checked.mch +0.01%
MinOpts (+0.01% to +0.02%)
Collection PDIFF
realworld.run.linux.x64.checked.mch +0.02%
smoke_tests.nativeaot.linux.x64.checked.mch +0.01%
FullOpts (+0.00% to +0.01%)
Collection PDIFF
realworld.run.linux.x64.checked.mch +0.01%

Details here


Throughput diffs for linux/x64 ran on linux/x64

Overall (-0.02%)
Collection PDIFF
smoke_tests.nativeaot.linux.x64.checked.mch -0.02%
MinOpts (-0.05%)
Collection PDIFF
smoke_tests.nativeaot.linux.x64.checked.mch -0.05%
FullOpts (-0.02%)
Collection PDIFF
smoke_tests.nativeaot.linux.x64.checked.mch -0.02%

Details here


@ryujit-bot
Copy link

Diff results for #92974

Throughput diffs

Throughput diffs for linux/x64 ran on linux/x64

Overall (-0.03% to -0.01%)
Collection PDIFF
smoke_tests.nativeaot.linux.x64.checked.mch -0.02%
benchmarks.run.linux.x64.checked.mch -0.01%
realworld.run.linux.x64.checked.mch -0.01%
libraries_tests.run.linux.x64.Release.mch -0.02%
benchmarks.run_tiered.linux.x64.checked.mch -0.03%
libraries_tests_no_tiered_compilation.run.linux.x64.Release.mch -0.01%
libraries.pmi.linux.x64.checked.mch -0.01%
coreclr_tests.run.linux.x64.checked.mch -0.03%
libraries.crossgen2.linux.x64.checked.mch -0.02%
benchmarks.run_pgo.linux.x64.checked.mch -0.02%
MinOpts (-0.07% to -0.04%)
Collection PDIFF
smoke_tests.nativeaot.linux.x64.checked.mch -0.05%
benchmarks.run.linux.x64.checked.mch -0.06%
realworld.run.linux.x64.checked.mch -0.05%
libraries_tests.run.linux.x64.Release.mch -0.06%
benchmarks.run_tiered.linux.x64.checked.mch -0.06%
libraries_tests_no_tiered_compilation.run.linux.x64.Release.mch -0.05%
libraries.pmi.linux.x64.checked.mch -0.04%
coreclr_tests.run.linux.x64.checked.mch -0.04%
libraries.crossgen2.linux.x64.checked.mch -0.07%
benchmarks.run_pgo.linux.x64.checked.mch -0.06%
FullOpts (-0.02% to -0.01%)
Collection PDIFF
smoke_tests.nativeaot.linux.x64.checked.mch -0.02%
benchmarks.run.linux.x64.checked.mch -0.01%
realworld.run.linux.x64.checked.mch -0.01%
libraries_tests.run.linux.x64.Release.mch -0.01%
benchmarks.run_tiered.linux.x64.checked.mch -0.01%
libraries_tests_no_tiered_compilation.run.linux.x64.Release.mch -0.01%
libraries.pmi.linux.x64.checked.mch -0.01%
coreclr_tests.run.linux.x64.checked.mch -0.01%
libraries.crossgen2.linux.x64.checked.mch -0.02%
benchmarks.run_pgo.linux.x64.checked.mch -0.01%

Details here


@ryujit-bot
Copy link

Diff results for #92974

Throughput diffs

Throughput diffs for linux/x64 ran on windows/x64

Overall (+0.00% to +0.01%)
Collection PDIFF
benchmarks.run.linux.x64.checked.mch +0.01%
benchmarks.run_pgo.linux.x64.checked.mch +0.01%
benchmarks.run_tiered.linux.x64.checked.mch +0.01%
coreclr_tests.run.linux.x64.checked.mch +0.01%
libraries.pmi.linux.x64.checked.mch +0.01%
libraries_tests.run.linux.x64.Release.mch +0.01%
libraries_tests_no_tiered_compilation.run.linux.x64.Release.mch +0.01%
realworld.run.linux.x64.checked.mch +0.01%
MinOpts (+0.01% to +0.03%)
Collection PDIFF
benchmarks.run.linux.x64.checked.mch +0.03%
benchmarks.run_pgo.linux.x64.checked.mch +0.03%
benchmarks.run_tiered.linux.x64.checked.mch +0.03%
coreclr_tests.run.linux.x64.checked.mch +0.02%
libraries.crossgen2.linux.x64.checked.mch +0.03%
libraries.pmi.linux.x64.checked.mch +0.01%
libraries_tests.run.linux.x64.Release.mch +0.03%
libraries_tests_no_tiered_compilation.run.linux.x64.Release.mch +0.03%
realworld.run.linux.x64.checked.mch +0.02%
smoke_tests.nativeaot.linux.x64.checked.mch +0.01%
FullOpts (+0.00% to +0.01%)
Collection PDIFF
benchmarks.run.linux.x64.checked.mch +0.01%
benchmarks.run_pgo.linux.x64.checked.mch +0.01%
benchmarks.run_tiered.linux.x64.checked.mch +0.01%
libraries.pmi.linux.x64.checked.mch +0.01%
libraries_tests.run.linux.x64.Release.mch +0.01%
realworld.run.linux.x64.checked.mch +0.01%

Throughput diffs for windows/x64 ran on windows/x64

Overall (-0.01% to -0.00%)
Collection PDIFF
coreclr_tests.run.windows.x64.checked.mch -0.01%
libraries.crossgen2.windows.x64.checked.mch -0.01%
smoke_tests.nativeaot.windows.x64.checked.mch -0.01%
MinOpts (-0.02% to +0.00%)
Collection PDIFF
benchmarks.run_pgo.windows.x64.checked.mch -0.01%
benchmarks.run_tiered.windows.x64.checked.mch -0.01%
coreclr_tests.run.windows.x64.checked.mch -0.01%
libraries.pmi.windows.x64.checked.mch -0.02%
libraries_tests.run.windows.x64.Release.mch -0.01%
realworld.run.windows.x64.checked.mch -0.01%
smoke_tests.nativeaot.windows.x64.checked.mch -0.02%
FullOpts (-0.01% to -0.00%)
Collection PDIFF
libraries.crossgen2.windows.x64.checked.mch -0.01%
smoke_tests.nativeaot.windows.x64.checked.mch -0.01%

Details here


Throughput diffs for windows/x86 ran on windows/x86

Overall (+0.00% to +0.01%)
Collection PDIFF
benchmarks.run_tiered.windows.x86.checked.mch +0.01%
coreclr_tests.run.windows.x86.checked.mch +0.01%
libraries.crossgen2.windows.x86.checked.mch +0.01%
libraries.pmi.windows.x86.checked.mch +0.01%
libraries_tests.run.windows.x86.Release.mch +0.01%
libraries_tests_no_tiered_compilation.run.windows.x86.Release.mch +0.01%
realworld.run.windows.x86.checked.mch +0.01%
MinOpts (+0.01% to +0.02%)
Collection PDIFF
benchmarks.run.windows.x86.checked.mch +0.01%
benchmarks.run_pgo.windows.x86.checked.mch +0.01%
benchmarks.run_tiered.windows.x86.checked.mch +0.01%
coreclr_tests.run.windows.x86.checked.mch +0.01%
libraries.crossgen2.windows.x86.checked.mch +0.01%
libraries.pmi.windows.x86.checked.mch +0.02%
libraries_tests.run.windows.x86.Release.mch +0.01%
libraries_tests_no_tiered_compilation.run.windows.x86.Release.mch +0.01%
realworld.run.windows.x86.checked.mch +0.01%
FullOpts (+0.00% to +0.01%)
Collection PDIFF
benchmarks.run_tiered.windows.x86.checked.mch +0.01%
libraries.crossgen2.windows.x86.checked.mch +0.01%
libraries.pmi.windows.x86.checked.mch +0.01%
libraries_tests_no_tiered_compilation.run.windows.x86.Release.mch +0.01%
realworld.run.windows.x86.checked.mch +0.01%

Details here


Throughput diffs for linux/x64 ran on linux/x64

Overall (-0.03% to -0.01%)
Collection PDIFF
libraries_tests_no_tiered_compilation.run.linux.x64.Release.mch -0.01%
libraries.pmi.linux.x64.checked.mch -0.01%
coreclr_tests.run.linux.x64.checked.mch -0.03%
realworld.run.linux.x64.checked.mch -0.01%
libraries.crossgen2.linux.x64.checked.mch -0.02%
benchmarks.run_tiered.linux.x64.checked.mch -0.03%
smoke_tests.nativeaot.linux.x64.checked.mch -0.02%
benchmarks.run_pgo.linux.x64.checked.mch -0.02%
libraries_tests.run.linux.x64.Release.mch -0.02%
benchmarks.run.linux.x64.checked.mch -0.01%
MinOpts (-0.07% to -0.04%)
Collection PDIFF
libraries_tests_no_tiered_compilation.run.linux.x64.Release.mch -0.05%
libraries.pmi.linux.x64.checked.mch -0.04%
coreclr_tests.run.linux.x64.checked.mch -0.04%
realworld.run.linux.x64.checked.mch -0.05%
libraries.crossgen2.linux.x64.checked.mch -0.07%
benchmarks.run_tiered.linux.x64.checked.mch -0.06%
smoke_tests.nativeaot.linux.x64.checked.mch -0.05%
benchmarks.run_pgo.linux.x64.checked.mch -0.06%
libraries_tests.run.linux.x64.Release.mch -0.06%
benchmarks.run.linux.x64.checked.mch -0.06%
FullOpts (-0.02% to -0.01%)
Collection PDIFF
libraries_tests_no_tiered_compilation.run.linux.x64.Release.mch -0.01%
libraries.pmi.linux.x64.checked.mch -0.01%
coreclr_tests.run.linux.x64.checked.mch -0.01%
realworld.run.linux.x64.checked.mch -0.01%
libraries.crossgen2.linux.x64.checked.mch -0.02%
benchmarks.run_tiered.linux.x64.checked.mch -0.01%
smoke_tests.nativeaot.linux.x64.checked.mch -0.02%
benchmarks.run_pgo.linux.x64.checked.mch -0.01%
libraries_tests.run.linux.x64.Release.mch -0.01%
benchmarks.run.linux.x64.checked.mch -0.01%

Details here


@MichalPetryka
Copy link
Contributor Author

@jkotas I think the arm32 atomic helper issue should be fixed in a separate PR (I can take a look at using the safe LLVM helpers later today) so this should be ready to merge.

@jkotas
Copy link
Member

jkotas commented Jan 25, 2024

Turns out a small bug in the helpers somehow trashed the stack.

What was this bug?

@jkotas
Copy link
Member

jkotas commented Jan 25, 2024

/azp run runtime-coreclr outerloop, runtime-nativeaot-outerloop

Copy link

Azure Pipelines successfully started running 2 pipeline(s).

@MichalPetryka
Copy link
Contributor Author

MichalPetryka commented Jan 25, 2024

Turns out a small bug in the helpers somehow trashed the stack.

What was this bug?

A missing cast to UINT8 from CHAR which was returned by InterlockedExchange8 which somehow overrode half of a long on stack with 0.

Copy link
Member

@jkotas jkotas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for making this happen!

@jkotas jkotas merged commit de9d791 into dotnet:main Jan 25, 2024
292 of 299 checks passed
@github-actions github-actions bot locked and limited conversation to collaborators Feb 25, 2024
[Intrinsic]
public static int CompareExchange(ref int location1, int value, int comparand)
{
#if TARGET_X86 || TARGET_AMD64 || TARGET_ARM64 || TARGET_RISCV64
return CompareExchange(ref location1, value, comparand);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a self-referential "must expand" intrinsic now.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-System.Threading community-contribution Indicates that the PR has been added by a community member new-api-needs-documentation
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[API Proposal]: Interlocked.CompareExchange for byte/short/sbyte/ushort