Visitar URL original
[RISC-V] Add Zacas support for Interlocked.CompareExchange by equmagg · Pull Request #137347 · dotnet/runtime · GitHub
Skip to content

[RISC-V] Add Zacas support for Interlocked.CompareExchange - #137347

Open
equmagg wants to merge 6 commits into
dotnet:mainfrom
equmagg:zacas-support
Open

equmagg wants to merge 6 commits into
dotnet:mainfrom
equmagg:zacas-support

Conversation

@equmagg

@equmagg equmagg commented Nov 11, 2026

Copy link
Copy Markdown
Contributor

Adds initial Zacas support for the existing 32-bit and 64-bit Interlocked.CompareExchange intrinsics on RISC-V64.
When Zacas is available, the JIT emits amocas.w or amocas.d in place of the lr/sc retry loop

PR largely follows the previous Zicond bring up work (#128799)

added

  • Linux feature detection through riscv_hwprobe, instruction set metadata, and runtime/compiler configuration
  • amocas instruction emission and disassembly
  • Register allocation changes to accommodate the shared comparand/result register and avoid the temporary registers required by the LR/SC sequence
  • Test coverage for successful and failed comparisons, zero and shared operands, live inputs, discarded results, floating-point bit patterns, reference clearing, and contention

The amocas sequence uses .aqrl and a preceding fence rw,rw. The fence orders preceding accesses before the comparison read even when the comparison fails, since a failed amocas does not provide release semantics by itself.
Zacas is enabled when detected and can be disabled with DOTNET_EnableRiscV64Zacas=0.

Validated on QEMU with Crossgen2, covering the Zacas path, lr/sc fallback, register stress, and four hart contention. With and without Zacas enablement.
Checked feature detection using mocked riscv_hwprobe responses with older, newer, and unavailable hwprobe headers

resolves #137345

Adds optional Zacas support to the JIT, allowing existing 32-bit and 64-bit Interlocked.CompareExchange intrinsics to use amocas.w and amocas.d
@github-actions github-actions Bot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Nov 11, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging @dotnet/jit-contrib for JIT-EE GUID update

@dotnet-policy-service dotnet-policy-service Bot added the community-contribution Indicates that the PR has been added by a community member label Nov 11, 2026
@equmagg
equmagg marked this pull request as draft November 11, 2026 14:34
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 7 pipeline(s).
8 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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

Comment thread src/native/minipal/cpufeatures.c Resolved
@am11 am11 added the arch-riscv Related to the RISC-V architecture label Nov 11, 2026
@am11

am11 commented Nov 11, 2026

Copy link
Copy Markdown
Member

BTW, I'm fixing another CAS issue with checked build, which will give you a conflict #137318.

@am11

am11 commented Nov 12, 2026

Copy link
Copy Markdown
Member

BTW, I'm fixing another CAS issue with checked build, which will give you a conflict #137318.

It's merged, please resolve conflicts and merge upstream main. When resolving, keep the sext.w of the comparand after genConsumeRegs(comparandOp) in the LR/SC path (that's the fix from #137318); doing it before can sign-extend a stale register if the comparand was spilled.

@equmagg

equmagg commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor Author

Conflicts resolved, thank you for the heads up

@equmagg
equmagg marked this pull request as ready for review November 12, 2026 17:05
@am11

am11 commented Nov 12, 2026

Copy link
Copy Markdown
Member

Formatting failure is related; you can apply the patch it has created and push.

@equmagg

equmagg commented Nov 12, 2026

Copy link
Copy Markdown
Contributor Author

Ah, I see. Will be on the lookout

@@ -525,21 +527,27 @@ int LinearScan::BuildNode(GenTree* tree)
{
srcCount++;
RefPosition* use = BuildUse(comparand);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

For the Zacas path, consider tgtPrefUse = use; here. amocas.w/d uses rd as both the comparand source and the destination (see the register operand table in rvwmo.adoc and zacas.adoc), so preferencing the target to the comparand register lets the mov in codegen be elided in the common case.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

reran the tests locally, tgtPrefUse = use improved 10 out of 314 test cases (passing result to non-inlined methods), others were identical.
Current tests did not catch any difference, not it sure if it justifies adding another one

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks. No need for another test, tgtPrefUse is only an allocation hint, and the existing KeepLive/Discard/SameOperand cases already cover both the shared and non-shared register paths for correctness.

@am11
am11 requested review from a team, jakobbotsch and tomeksowi November 12, 2026 17:56
@am11

am11 commented Nov 12, 2026 •

Copy link
Copy Markdown
Member

LGTM, my (RVA22) device doesn't have Zacas, maybe @filipnavara if you could give it a try on yours, that would be great. I'm running AOT smoke tests against this PR's branch, let's see:

linux-riscv64: https://github.com/am11/CrossRepoCITesting/actions/runs/43275277170
linux-musl-riscv64: https://github.com/am11/CrossRepoCITesting/actions/runs/43275283777

Update: both passed, ✅

@tomeksowi tomeksowi left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nice to see another RVA23 extension supported

Comment on lines 2140 to 2143
// NOTE: `genConsumeAddress` marks consumed register as not a GC pointer, assuming the input
// registers die at the first generated instruction. However, here the input registers are reused,
// so mark the location register as a GC pointer until code generation for this node is finished.
gcInfo.gcMarkRegPtrVal(loc, locOp->TypeGet());

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

IIRC it's because LR/SC compare-and-swap was a loop, may be safe to do only under !useZacas

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think it's still needed for Zacas. genConsumeAddress assumes the address dies at the first emitted instruction, but here loc is only read by amocas, after the comparand mov and the fence. In fully interruptible code, a GC between those could move the object while loc isn't reported, so I'd keep marking it unconditionally.

@MichalPetryka

Copy link
Copy Markdown
Contributor

Ideally small types should be handled in a followup too to keep them consistent.

@filipnavara

Copy link
Copy Markdown
Member

LGTM, my (RVA22) device doesn't have Zacas, maybe @filipnavara if you could give it a try on yours, that would be great.

I am away from my device farm and mostly offline till the end of the month, unfortunately.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

arch-riscv Related to the RISC-V architecture area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI community-contribution Indicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[RISC-V] Zacas support for Interlocked.CompareExchange

5 participants