Skip to content

arm64: Clean up SVE embedded masked codegen - #127164

Merged
dhartglassMSFT merged 12 commits into
dotnet:mainfrom
ylpoonlg:github-movprfx_refactor_3
Jun 30, 2026
Merged

arm64: Clean up SVE embedded masked codegen#127164
dhartglassMSFT merged 12 commits into
dotnet:mainfrom
ylpoonlg:github-movprfx_refactor_3

Conversation

@ylpoonlg

Copy link
Copy Markdown
Contributor

This PR is the last part for #115508, with the following changes:

  • Cleanup to hwintrinsiccodegenarm64.cpp:

    • Move the embedded masked block to a new function genEmbeddedMaskedHWIntrinsic.
    • Combine codepaths for different number of operand cases and centralize movprfx logic.
  • Optimizations to movprfx usage in embedded masked operation codegen:

    • Replace predicated movprfx with unpredicated movprfx when mask is all-true. Unpredicated movprfx is generally preferred due to performance.
    • Allow zero falseOp to be contained when mask is not all-true so that zeroing predicated movprfx can be used.
    • Allow unary embedded masked ops to use movprfx. Unary embedded masked ops are not RMW instructions, but may also support movprfx, which require the target register to be delayed free in LSRA.
  • Fixing the Sve HardwareIntrinsics tests ConditionalSelect_ZeroOp calls: The falseOp->IsVectorZero branch in the codegen was previously untested because the zero vector was passed as a local variable rather than a constant vector. The zero vector needs to be passed directly into the ConditionalSelect intrinsic in the test templates.

* Move the embedded masked block to a new function.
* Combine codepaths for different number of operand cases.
* Optimise predicated movprfx into unpredicated movprfx when mask is all-true.
* Allow zero falseOp to be contained when mask is not all-true.
* Fix Sve HWIntrin tests ConditionalSelect ZeroOp. The zero vector needs
to be passed directly as constant such that the falseOp->IsVectorZero
branch can be tested.
* Fix LSRA delay free to allow unary embedded masked ops to use movprfx.
@github-actionsgithub-actionsBot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Apr 20, 2026
@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Apr 20, 2026
@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.

@ylpoonlg

Copy link
Copy Markdown
ContributorAuthor

Example SPMI asmdiffs:

@@ -22,11 +22,11 @@
movz x0, #0xD1FFAB1E // data for <unknown class>:<unknown field>
movk x0, #0xD1FFAB1E LSL #16
movk x0, #0xD1FFAB1E LSL #32
ldr q17, [x0]
ptrue p0.d
- movprfx z18.d, p0/z, z16.d+ movprfx z18, z16
fmla z18.d, p0/m, z17.d, z17.d
str q18, [x0]

Replaces predicated movprfx with unpredicated movprfx when predicate is true.

@@ -20,31 +20,30 @@
;; size=16 bbWeight=1 PerfScore 3.50
G_M32226_IG02: ; bbWeight=1, gcrefRegs=0000 {}, byrefRegs=0000 {}, byref
ldr q16, [fp, #0x20] // [V00 arg0]
ldr q17, [fp, #0x10] // [V01 arg1]
ptrue p0.b
- movprfx z16.b, p0/z, z16.b
smax z16.b, p0/m, z16.b, z17.b
mov v0.16b, v16.16b

Removes unnecessary movprfx when moving the same register and predicate is all-true.

@@ -195,14 +191,12 @@
blr x1 // code for <unknown method>
; gcrRegs -[x0]
ldp q1, q3, [x19, #0x30]
mov v2.16b, v3.16b
ptrue p0.d
- movi v0.4s, #0
movprfx z4, z1
faddp z4.d, p0/m, z4.d, z2.d
- sel z4.d, p0, z4.d, z0.d
mvni v0.4s, #0
mov x0, x19
; gcrRegs +[x0]
mov w1, #1
mov x2, x21

Removes unnecessary selects and contain zero vector when mask is all-true.

 ; gcrRegs -[x0]
ldr q0, [x19, #0x18]
ldr q1, [x19, #0x28]
ptrue p0.d
cmpne p0.d, p0/z, z0.d, #0
- movi v3.4s, #0+ movprfx z3.d, p0/z, z3.d
frintn z3.d, p0/m, z1.d
movi v2.4s, #0
mov x0, x19
; gcrRegs +[x0]
mov w1, #1

Contains the zero vector and use zeroing movprfx.

@@ -150,13 +150,14 @@
ptrue p0.s
cmpne p0.s, p0/z, z8.s, #0
movi v16.4s, #0
mov z12.d, z9.d
fcvtnt z12.s, p0/m, z10.d
+ sel z12.s, p0, z12.s, z16.s
str q12, [fp, #0x20] // [V07 tmp6]
b G_M36822_IG05

Fixes a bug with inactive lanes for ConvertToSingleOdd. This was revealed by the changes to the test templates.

@ylpoonlg
ylpoonlg marked this pull request as ready for review April 23, 2026 16:28
@ylpoonlg

Copy link
Copy Markdown
ContributorAuthor

jitstressregs passes locally.

@dotnet/arm64-contrib @a74nh@dhartglassMSFT

@ylpoonlg

Copy link
Copy Markdown
ContributorAuthor

error : (NETCORE_ENGINEERING_TELEMETRY=Test) Test JIT/opt/SVE/ConstantMasks/ConstantMasks.cmd has failed.

Some optimization tests are failing, I will look into them further.

Comment threadsrc/coreclr/jit/lsraarm64.cpp
Comment threadsrc/coreclr/jit/lsraarm64.cpp
Comment threadsrc/coreclr/jit/hwintrinsiccodegenarm64.cpp Outdated
Comment threadsrc/coreclr/jit/hwintrinsiccodegenarm64.cpp Outdated
@ylpoonlg

Copy link
Copy Markdown
ContributorAuthor

There is still a failing SVE opt test ConstantMasks:

 552: G_M15649_IG02:
553: ptrue p0.s
554: abs z16.s, p0/m, z0.s
555: mov v0.16b, v16.16b
556: movz x0, #0xD1FFAB1E // code for ConstantMasks:Consume[System.Numerics.Vector`1[int]](System.Numerics.Vector`1[int])
next:179 !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: match on wrong line

The LSRA change caused an extra mov v0.16b, v16.16b, but I have not been able to prioritize the destination register over op1 (any ideas would be appreciated). This was done to allow for movprfx usage, but in this case the ptrue suppressed it, so it doesn't really need to be delayed free. Maybe I should revert to using SVE mov instead of movprfx for now, and leave this for #107134.

@dhartglassMSFT

Copy link
Copy Markdown
Contributor

There is still a failing SVE opt test ConstantMasks:

 552: G_M15649_IG02:
553: ptrue p0.s
554: abs z16.s, p0/m, z0.s
555: mov v0.16b, v16.16b
556: movz x0, #0xD1FFAB1E // code for ConstantMasks:Consume[System.Numerics.Vector`1[int]](System.Numerics.Vector`1[int])
next:179 !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: match on wrong line

The LSRA change caused an extra mov v0.16b, v16.16b, but I have not been able to prioritize the destination register over op1 (any ideas would be appreciated). This was done to allow for movprfx usage, but in this case the ptrue suppressed it, so it doesn't really need to be delayed free. Maybe I should revert to using SVE mov instead of movprfx for now, and leave this for #107134.

Hey @ylpoonlg@a74nh following up on this. I may have lost some context, but during lsra we know whether the mask is all true, correct? In any case let me know if you needed further follow-up here, sorry for the delay

@ylpoonlg

Copy link
Copy Markdown
ContributorAuthor

There is still a failing SVE opt test ConstantMasks:

 552: G_M15649_IG02:
553: ptrue p0.s
554: abs z16.s, p0/m, z0.s
555: mov v0.16b, v16.16b
556: movz x0, #0xD1FFAB1E // code for ConstantMasks:Consume[System.Numerics.Vector`1[int]](System.Numerics.Vector`1[int])
next:179 !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: match on wrong line

The LSRA change caused an extra mov v0.16b, v16.16b, but I have not been able to prioritize the destination register over op1 (any ideas would be appreciated). This was done to allow for movprfx usage, but in this case the ptrue suppressed it, so it doesn't really need to be delayed free. Maybe I should revert to using SVE mov instead of movprfx for now, and leave this for #107134.

Hey @ylpoonlg@a74nh following up on this. I may have lost some context, but during lsra we know whether the mask is all true, correct? In any case let me know if you needed further follow-up here, sorry for the delay

Thanks for looking at this. I think currently lsra is delay-freeing operands for all RMW instructions(#107134), but this is fine for now. The main issue here is the unary embedded masked operations, since they are not RMW but also support MOVPRFX. I attempted to enable its usage by allowing delay free in lsra, but looks like it is not assigning the registers optimally, causing the test failure:
For example with

abs z16.s, p0/m, z0.s
mov v0.16b, v16.16b

the extra mov is unnecessary if it can use the destination register directly and use a different source register:

abs z0.s, p0/m, z16.s

If this lsra is too complicated to fix in this PR, I can remove this particular optimization and not use MOVPRFX with unary embedded masked operations for now.

@a74nh

Copy link
Copy Markdown
Contributor

@ylpoonlg : I've taken a look at this and made some fixes in LSRA, which fix up the regressions in both Abs and ConvertToSingleOdd. I don't have the permissions to push directly to this PR, so could you please take a look at my two commits and add them into this PR (assuming you're happy with the changes 😄 ).

https://github.com/dotnet/runtime/compare/main...a74nh:runtime:github-movprfx_refactor_3?expand=1

@a74nha74nh mentioned this pull request Jun 24, 2026
20 tasks
@dhartglassMSFT

Copy link
Copy Markdown
Contributor

/azp run runtime-coreclr jitstressregs

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@dhartglassMSFT

Copy link
Copy Markdown
Contributor

/azp run runtime-coreclr jitstressregs

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@dhartglassMSFT

Copy link
Copy Markdown
Contributor

last regstress hit a known issue, kicking off a new one

@a74nh

Copy link
Copy Markdown
Contributor

@dhartglassMSFT - did something go wrong with the stress run again?

@dhartglassMSFT

Copy link
Copy Markdown
Contributor

/azp run runtime-coreclr jitstressregs

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@dhartglassMSFT

Copy link
Copy Markdown
Contributor

@dhartglassMSFT - did something go wrong with the stress run again?

It will surely work on the third try

@dhartglassMSFT

Copy link
Copy Markdown
Contributor

@a74nh I took another look, unfortunately the SPMI failures appear related.

[01:51:17] ISSUE: <ASSERT> #61471 D:\a\_work\1\s\src\coreclr\jit\hwintrinsiccodegenarm64.cpp (824) - Assertion failed '(targetReg != intrin.op2->GetRegNum()) || genIsSameLocalVar(rmwOp, intrin.op2)' in 'SveBenchmarks.ComplexMultiply:SveComplexMultiply():this' during 'Generate code' (IL size 514; hash 0xcf12aa28; FullOpts)

@dhartglassMSFT

dhartglassMSFT commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

@a74nh I had missed there were also these two in the SPMI output.

This now should be al the failures, apologies for missing these on my first glance yesterday
(same assert twice)

[17:22:24] ISSUE: <ASM_DIFF> main method 15075 of size 301 differs
[17:22:24] ISSUE: <ASM_DIFF> main method 18555 of size 535 differs
[17:22:24] ISSUE: <ASSERT> #21871 D:\a\_work\1\s\src\coreclr\jit\hwintrinsiccodegenarm64.cpp (854) - Assertion failed 'canRepairTargetOverlap || (targetReg != intrin.op2->GetRegNum()) || genIsSameLocalVar(rmwOp, intrin.op2)' in 'SveBenchmarks.ComplexMultiply:SveComplexMultiply():this' during 'Generate code' (IL size 514; hash 0xcf12aa28; FullOpts)
[17:22:24] [17:22:24] ISSUE: <ASM_DIFF> main method 11328 of size 148 differs
[17:22:24] ISSUE: <ASSERT> #17808 D:\a\_work\1\s\src\coreclr\jit\hwintrinsiccodegenarm64.cpp (854) - Assertion failed 'canRepairTargetOverlap || (targetReg != intrin.op2->GetRegNum()) || genIsSameLocalVar(rmwOp, intrin.op2)' in 'SveBenchmarks.Logarithm:SveLogarithm():this' during 'Generate code' (IL size 666; hash 0xfd45ed08; FullOpts)
[17:22:24] [17:22:24] Compilation failures

@a74nh

Copy link
Copy Markdown
Contributor

@a74nh I had missed there were also these two in the SPMI output.

This now should be al the failures, apologies for missing these on my first glance yesterday (same assert twice)

[17:22:24] ISSUE: <ASM_DIFF> main method 15075 of size 301 differs
[17:22:24] ISSUE: <ASM_DIFF> main method 18555 of size 535 differs
[17:22:24] ISSUE: <ASSERT> #21871 D:\a\_work\1\s\src\coreclr\jit\hwintrinsiccodegenarm64.cpp (854) - Assertion failed 'canRepairTargetOverlap || (targetReg != intrin.op2->GetRegNum()) || genIsSameLocalVar(rmwOp, intrin.op2)' in 'SveBenchmarks.ComplexMultiply:SveComplexMultiply():this' during 'Generate code' (IL size 514; hash 0xcf12aa28; FullOpts)
[17:22:24] [17:22:24] ISSUE: <ASM_DIFF> main method 11328 of size 148 differs
[17:22:24] ISSUE: <ASSERT> #17808 D:\a\_work\1\s\src\coreclr\jit\hwintrinsiccodegenarm64.cpp (854) - Assertion failed 'canRepairTargetOverlap || (targetReg != intrin.op2->GetRegNum()) || genIsSameLocalVar(rmwOp, intrin.op2)' in 'SveBenchmarks.Logarithm:SveLogarithm():this' during 'Generate code' (IL size 666; hash 0xfd45ed08; FullOpts)
[17:22:24] [17:22:24] Compilation failures

These should be fixed now too...

@dhartglassMSFT
dhartglassMSFT enabled auto-merge (squash) June 30, 2026 19:12
@dhartglassMSFT
dhartglassMSFT merged commit 411b771 into dotnet:mainJun 30, 2026
145 of 150 checks passed
@dhartglassMSFT

Copy link
Copy Markdown
Contributor

I merged this, thanks @a74nh and @ylpoon-arm for the fix here!

@dotnet-milestone-botdotnet-milestone-botBot added this to the 11.0-preview7 milestone Jul 1, 2026
@JulieLeeMSFTJulieLeeMSFT added the arm-sve Work related to arm64 SVE/SVE2 support label Jul 1, 2026
eiriktsarpalis pushed a commit that referenced this pull request Jul 15, 2026
This PR is the last part for #115508, with the following changes:
* Cleanup to `hwintrinsiccodegenarm64.cpp`:
* Move the embedded masked block to a new function
`genEmbeddedMaskedHWIntrinsic`.
* Combine codepaths for different number of operand cases and centralize
movprfx logic.
* Optimizations to movprfx usage in embedded masked operation codegen:
* Replace predicated movprfx with unpredicated movprfx when mask is
all-true. Unpredicated movprfx is generally preferred due to
performance.
* Allow zero falseOp to be contained when mask is not all-true so that
zeroing predicated movprfx can be used.
* Allow unary embedded masked ops to use movprfx. Unary embedded masked
ops are not RMW instructions, but may also support movprfx, which
require the target register to be delayed free in LSRA.
* Fixing the Sve HardwareIntrinsics tests `ConditionalSelect_ZeroOp`
calls: The `falseOp->IsVectorZero` branch in the codegen was previously
untested because the zero vector was passed as a local variable rather
than a constant vector. The zero vector needs to be passed directly into
the `ConditionalSelect` intrinsic in the test templates.
---------
Co-authored-by: Alan Hayward <alan.hayward@arm.com>
Co-authored-by: Yat Long Poon <yatlong.poon@arm.com>
Co-authored-by: dhartglassMSFT <dhartglass+github@microsoft.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Aug 1, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMIarm-sveWork related to arm64 SVE/SVE2 supportcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@ylpoonlg@dhartglassMSFT@a74nh@JulieLeeMSFT@ylpoon-arm
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
arm64: Clean up SVE embedded masked codegen by ylpoonlg · Pull Request #127164 · dotnet/runtime · GitHub
Skip to content

arm64: Clean up SVE embedded masked codegen - #127164

Merged
dhartglassMSFT merged 12 commits into
dotnet:mainfrom
ylpoonlg:github-movprfx_refactor_3
Jun 30, 2026
Merged

arm64: Clean up SVE embedded masked codegen#127164
dhartglassMSFT merged 12 commits into
dotnet:mainfrom
ylpoonlg:github-movprfx_refactor_3

Conversation

@ylpoonlg

Copy link
Copy Markdown
Contributor

This PR is the last part for #115508, with the following changes:

  • Cleanup to hwintrinsiccodegenarm64.cpp:

    • Move the embedded masked block to a new function genEmbeddedMaskedHWIntrinsic.
    • Combine codepaths for different number of operand cases and centralize movprfx logic.
  • Optimizations to movprfx usage in embedded masked operation codegen:

    • Replace predicated movprfx with unpredicated movprfx when mask is all-true. Unpredicated movprfx is generally preferred due to performance.
    • Allow zero falseOp to be contained when mask is not all-true so that zeroing predicated movprfx can be used.
    • Allow unary embedded masked ops to use movprfx. Unary embedded masked ops are not RMW instructions, but may also support movprfx, which require the target register to be delayed free in LSRA.
  • Fixing the Sve HardwareIntrinsics tests ConditionalSelect_ZeroOp calls: The falseOp->IsVectorZero branch in the codegen was previously untested because the zero vector was passed as a local variable rather than a constant vector. The zero vector needs to be passed directly into the ConditionalSelect intrinsic in the test templates.

* Move the embedded masked block to a new function.
* Combine codepaths for different number of operand cases.
* Optimise predicated movprfx into unpredicated movprfx when mask is all-true.
* Allow zero falseOp to be contained when mask is not all-true.
* Fix Sve HWIntrin tests ConditionalSelect ZeroOp. The zero vector needs
to be passed directly as constant such that the falseOp->IsVectorZero
branch can be tested.
* Fix LSRA delay free to allow unary embedded masked ops to use movprfx.
@github-actionsgithub-actionsBot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Apr 20, 2026
@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Apr 20, 2026
@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.

@ylpoonlg

Copy link
Copy Markdown
ContributorAuthor

Example SPMI asmdiffs:

@@ -22,11 +22,11 @@
movz x0, #0xD1FFAB1E // data for <unknown class>:<unknown field>
movk x0, #0xD1FFAB1E LSL #16
movk x0, #0xD1FFAB1E LSL #32
ldr q17, [x0]
ptrue p0.d
- movprfx z18.d, p0/z, z16.d+ movprfx z18, z16
fmla z18.d, p0/m, z17.d, z17.d
str q18, [x0]

Replaces predicated movprfx with unpredicated movprfx when predicate is true.

@@ -20,31 +20,30 @@
;; size=16 bbWeight=1 PerfScore 3.50
G_M32226_IG02: ; bbWeight=1, gcrefRegs=0000 {}, byrefRegs=0000 {}, byref
ldr q16, [fp, #0x20] // [V00 arg0]
ldr q17, [fp, #0x10] // [V01 arg1]
ptrue p0.b
- movprfx z16.b, p0/z, z16.b
smax z16.b, p0/m, z16.b, z17.b
mov v0.16b, v16.16b

Removes unnecessary movprfx when moving the same register and predicate is all-true.

@@ -195,14 +191,12 @@
blr x1 // code for <unknown method>
; gcrRegs -[x0]
ldp q1, q3, [x19, #0x30]
mov v2.16b, v3.16b
ptrue p0.d
- movi v0.4s, #0
movprfx z4, z1
faddp z4.d, p0/m, z4.d, z2.d
- sel z4.d, p0, z4.d, z0.d
mvni v0.4s, #0
mov x0, x19
; gcrRegs +[x0]
mov w1, #1
mov x2, x21

Removes unnecessary selects and contain zero vector when mask is all-true.

 ; gcrRegs -[x0]
ldr q0, [x19, #0x18]
ldr q1, [x19, #0x28]
ptrue p0.d
cmpne p0.d, p0/z, z0.d, #0
- movi v3.4s, #0+ movprfx z3.d, p0/z, z3.d
frintn z3.d, p0/m, z1.d
movi v2.4s, #0
mov x0, x19
; gcrRegs +[x0]
mov w1, #1

Contains the zero vector and use zeroing movprfx.

@@ -150,13 +150,14 @@
ptrue p0.s
cmpne p0.s, p0/z, z8.s, #0
movi v16.4s, #0
mov z12.d, z9.d
fcvtnt z12.s, p0/m, z10.d
+ sel z12.s, p0, z12.s, z16.s
str q12, [fp, #0x20] // [V07 tmp6]
b G_M36822_IG05

Fixes a bug with inactive lanes for ConvertToSingleOdd. This was revealed by the changes to the test templates.

@ylpoonlg
ylpoonlg marked this pull request as ready for review April 23, 2026 16:28
@ylpoonlg

Copy link
Copy Markdown
ContributorAuthor

jitstressregs passes locally.

@dotnet/arm64-contrib @a74nh@dhartglassMSFT

@ylpoonlg

Copy link
Copy Markdown
ContributorAuthor

error : (NETCORE_ENGINEERING_TELEMETRY=Test) Test JIT/opt/SVE/ConstantMasks/ConstantMasks.cmd has failed.

Some optimization tests are failing, I will look into them further.

Comment threadsrc/coreclr/jit/lsraarm64.cpp
Comment threadsrc/coreclr/jit/lsraarm64.cpp
Comment threadsrc/coreclr/jit/hwintrinsiccodegenarm64.cpp Outdated
Comment threadsrc/coreclr/jit/hwintrinsiccodegenarm64.cpp Outdated
@ylpoonlg

Copy link
Copy Markdown
ContributorAuthor

There is still a failing SVE opt test ConstantMasks:

 552: G_M15649_IG02:
553: ptrue p0.s
554: abs z16.s, p0/m, z0.s
555: mov v0.16b, v16.16b
556: movz x0, #0xD1FFAB1E // code for ConstantMasks:Consume[System.Numerics.Vector`1[int]](System.Numerics.Vector`1[int])
next:179 !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: match on wrong line

The LSRA change caused an extra mov v0.16b, v16.16b, but I have not been able to prioritize the destination register over op1 (any ideas would be appreciated). This was done to allow for movprfx usage, but in this case the ptrue suppressed it, so it doesn't really need to be delayed free. Maybe I should revert to using SVE mov instead of movprfx for now, and leave this for #107134.

@dhartglassMSFT

Copy link
Copy Markdown
Contributor

There is still a failing SVE opt test ConstantMasks:

 552: G_M15649_IG02:
553: ptrue p0.s
554: abs z16.s, p0/m, z0.s
555: mov v0.16b, v16.16b
556: movz x0, #0xD1FFAB1E // code for ConstantMasks:Consume[System.Numerics.Vector`1[int]](System.Numerics.Vector`1[int])
next:179 !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: match on wrong line

The LSRA change caused an extra mov v0.16b, v16.16b, but I have not been able to prioritize the destination register over op1 (any ideas would be appreciated). This was done to allow for movprfx usage, but in this case the ptrue suppressed it, so it doesn't really need to be delayed free. Maybe I should revert to using SVE mov instead of movprfx for now, and leave this for #107134.

Hey @ylpoonlg@a74nh following up on this. I may have lost some context, but during lsra we know whether the mask is all true, correct? In any case let me know if you needed further follow-up here, sorry for the delay

@ylpoonlg

Copy link
Copy Markdown
ContributorAuthor

There is still a failing SVE opt test ConstantMasks:

 552: G_M15649_IG02:
553: ptrue p0.s
554: abs z16.s, p0/m, z0.s
555: mov v0.16b, v16.16b
556: movz x0, #0xD1FFAB1E // code for ConstantMasks:Consume[System.Numerics.Vector`1[int]](System.Numerics.Vector`1[int])
next:179 !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: match on wrong line

The LSRA change caused an extra mov v0.16b, v16.16b, but I have not been able to prioritize the destination register over op1 (any ideas would be appreciated). This was done to allow for movprfx usage, but in this case the ptrue suppressed it, so it doesn't really need to be delayed free. Maybe I should revert to using SVE mov instead of movprfx for now, and leave this for #107134.

Hey @ylpoonlg@a74nh following up on this. I may have lost some context, but during lsra we know whether the mask is all true, correct? In any case let me know if you needed further follow-up here, sorry for the delay

Thanks for looking at this. I think currently lsra is delay-freeing operands for all RMW instructions(#107134), but this is fine for now. The main issue here is the unary embedded masked operations, since they are not RMW but also support MOVPRFX. I attempted to enable its usage by allowing delay free in lsra, but looks like it is not assigning the registers optimally, causing the test failure:
For example with

abs z16.s, p0/m, z0.s
mov v0.16b, v16.16b

the extra mov is unnecessary if it can use the destination register directly and use a different source register:

abs z0.s, p0/m, z16.s

If this lsra is too complicated to fix in this PR, I can remove this particular optimization and not use MOVPRFX with unary embedded masked operations for now.

@a74nh

Copy link
Copy Markdown
Contributor

@ylpoonlg : I've taken a look at this and made some fixes in LSRA, which fix up the regressions in both Abs and ConvertToSingleOdd. I don't have the permissions to push directly to this PR, so could you please take a look at my two commits and add them into this PR (assuming you're happy with the changes 😄 ).

https://github.com/dotnet/runtime/compare/main...a74nh:runtime:github-movprfx_refactor_3?expand=1

@a74nha74nh mentioned this pull request Jun 24, 2026
20 tasks
@dhartglassMSFT

Copy link
Copy Markdown
Contributor

/azp run runtime-coreclr jitstressregs

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@dhartglassMSFT

Copy link
Copy Markdown
Contributor

/azp run runtime-coreclr jitstressregs

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@dhartglassMSFT

Copy link
Copy Markdown
Contributor

last regstress hit a known issue, kicking off a new one

@a74nh

Copy link
Copy Markdown
Contributor

@dhartglassMSFT - did something go wrong with the stress run again?

@dhartglassMSFT

Copy link
Copy Markdown
Contributor

/azp run runtime-coreclr jitstressregs

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@dhartglassMSFT

Copy link
Copy Markdown
Contributor

@dhartglassMSFT - did something go wrong with the stress run again?

It will surely work on the third try

@dhartglassMSFT

Copy link
Copy Markdown
Contributor

@a74nh I took another look, unfortunately the SPMI failures appear related.

[01:51:17] ISSUE: <ASSERT> #61471 D:\a\_work\1\s\src\coreclr\jit\hwintrinsiccodegenarm64.cpp (824) - Assertion failed '(targetReg != intrin.op2->GetRegNum()) || genIsSameLocalVar(rmwOp, intrin.op2)' in 'SveBenchmarks.ComplexMultiply:SveComplexMultiply():this' during 'Generate code' (IL size 514; hash 0xcf12aa28; FullOpts)

@dhartglassMSFT

dhartglassMSFT commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

@a74nh I had missed there were also these two in the SPMI output.

This now should be al the failures, apologies for missing these on my first glance yesterday
(same assert twice)

[17:22:24] ISSUE: <ASM_DIFF> main method 15075 of size 301 differs
[17:22:24] ISSUE: <ASM_DIFF> main method 18555 of size 535 differs
[17:22:24] ISSUE: <ASSERT> #21871 D:\a\_work\1\s\src\coreclr\jit\hwintrinsiccodegenarm64.cpp (854) - Assertion failed 'canRepairTargetOverlap || (targetReg != intrin.op2->GetRegNum()) || genIsSameLocalVar(rmwOp, intrin.op2)' in 'SveBenchmarks.ComplexMultiply:SveComplexMultiply():this' during 'Generate code' (IL size 514; hash 0xcf12aa28; FullOpts)
[17:22:24] [17:22:24] ISSUE: <ASM_DIFF> main method 11328 of size 148 differs
[17:22:24] ISSUE: <ASSERT> #17808 D:\a\_work\1\s\src\coreclr\jit\hwintrinsiccodegenarm64.cpp (854) - Assertion failed 'canRepairTargetOverlap || (targetReg != intrin.op2->GetRegNum()) || genIsSameLocalVar(rmwOp, intrin.op2)' in 'SveBenchmarks.Logarithm:SveLogarithm():this' during 'Generate code' (IL size 666; hash 0xfd45ed08; FullOpts)
[17:22:24] [17:22:24] Compilation failures

@a74nh

Copy link
Copy Markdown
Contributor

@a74nh I had missed there were also these two in the SPMI output.

This now should be al the failures, apologies for missing these on my first glance yesterday (same assert twice)

[17:22:24] ISSUE: <ASM_DIFF> main method 15075 of size 301 differs
[17:22:24] ISSUE: <ASM_DIFF> main method 18555 of size 535 differs
[17:22:24] ISSUE: <ASSERT> #21871 D:\a\_work\1\s\src\coreclr\jit\hwintrinsiccodegenarm64.cpp (854) - Assertion failed 'canRepairTargetOverlap || (targetReg != intrin.op2->GetRegNum()) || genIsSameLocalVar(rmwOp, intrin.op2)' in 'SveBenchmarks.ComplexMultiply:SveComplexMultiply():this' during 'Generate code' (IL size 514; hash 0xcf12aa28; FullOpts)
[17:22:24] [17:22:24] ISSUE: <ASM_DIFF> main method 11328 of size 148 differs
[17:22:24] ISSUE: <ASSERT> #17808 D:\a\_work\1\s\src\coreclr\jit\hwintrinsiccodegenarm64.cpp (854) - Assertion failed 'canRepairTargetOverlap || (targetReg != intrin.op2->GetRegNum()) || genIsSameLocalVar(rmwOp, intrin.op2)' in 'SveBenchmarks.Logarithm:SveLogarithm():this' during 'Generate code' (IL size 666; hash 0xfd45ed08; FullOpts)
[17:22:24] [17:22:24] Compilation failures

These should be fixed now too...

@dhartglassMSFT
dhartglassMSFT enabled auto-merge (squash) June 30, 2026 19:12
@dhartglassMSFT
dhartglassMSFT merged commit 411b771 into dotnet:mainJun 30, 2026
145 of 150 checks passed
@dhartglassMSFT

Copy link
Copy Markdown
Contributor

I merged this, thanks @a74nh and @ylpoon-arm for the fix here!

@dotnet-milestone-botdotnet-milestone-botBot added this to the 11.0-preview7 milestone Jul 1, 2026
@JulieLeeMSFTJulieLeeMSFT added the arm-sve Work related to arm64 SVE/SVE2 support label Jul 1, 2026
eiriktsarpalis pushed a commit that referenced this pull request Jul 15, 2026
This PR is the last part for #115508, with the following changes:
* Cleanup to `hwintrinsiccodegenarm64.cpp`:
* Move the embedded masked block to a new function
`genEmbeddedMaskedHWIntrinsic`.
* Combine codepaths for different number of operand cases and centralize
movprfx logic.
* Optimizations to movprfx usage in embedded masked operation codegen:
* Replace predicated movprfx with unpredicated movprfx when mask is
all-true. Unpredicated movprfx is generally preferred due to
performance.
* Allow zero falseOp to be contained when mask is not all-true so that
zeroing predicated movprfx can be used.
* Allow unary embedded masked ops to use movprfx. Unary embedded masked
ops are not RMW instructions, but may also support movprfx, which
require the target register to be delayed free in LSRA.
* Fixing the Sve HardwareIntrinsics tests `ConditionalSelect_ZeroOp`
calls: The `falseOp->IsVectorZero` branch in the codegen was previously
untested because the zero vector was passed as a local variable rather
than a constant vector. The zero vector needs to be passed directly into
the `ConditionalSelect` intrinsic in the test templates.
---------
Co-authored-by: Alan Hayward <alan.hayward@arm.com>
Co-authored-by: Yat Long Poon <yatlong.poon@arm.com>
Co-authored-by: dhartglassMSFT <dhartglass+github@microsoft.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Aug 1, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMIarm-sveWork related to arm64 SVE/SVE2 supportcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@ylpoonlg@dhartglassMSFT@a74nh@JulieLeeMSFT@ylpoon-arm
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' arm64: Clean up SVE embedded masked codegen by ylpoonlg · Pull Request #127164 · dotnet/runtime · GitHub
Skip to content

arm64: Clean up SVE embedded masked codegen - #127164

Merged
dhartglassMSFT merged 12 commits into
dotnet:mainfrom
ylpoonlg:github-movprfx_refactor_3
Jun 30, 2026
Merged

arm64: Clean up SVE embedded masked codegen#127164
dhartglassMSFT merged 12 commits into
dotnet:mainfrom
ylpoonlg:github-movprfx_refactor_3

Conversation

@ylpoonlg

Copy link
Copy Markdown
Contributor

This PR is the last part for #115508, with the following changes:

  • Cleanup to hwintrinsiccodegenarm64.cpp:

    • Move the embedded masked block to a new function genEmbeddedMaskedHWIntrinsic.
    • Combine codepaths for different number of operand cases and centralize movprfx logic.
  • Optimizations to movprfx usage in embedded masked operation codegen:

    • Replace predicated movprfx with unpredicated movprfx when mask is all-true. Unpredicated movprfx is generally preferred due to performance.
    • Allow zero falseOp to be contained when mask is not all-true so that zeroing predicated movprfx can be used.
    • Allow unary embedded masked ops to use movprfx. Unary embedded masked ops are not RMW instructions, but may also support movprfx, which require the target register to be delayed free in LSRA.
  • Fixing the Sve HardwareIntrinsics tests ConditionalSelect_ZeroOp calls: The falseOp->IsVectorZero branch in the codegen was previously untested because the zero vector was passed as a local variable rather than a constant vector. The zero vector needs to be passed directly into the ConditionalSelect intrinsic in the test templates.

* Move the embedded masked block to a new function.
* Combine codepaths for different number of operand cases.
* Optimise predicated movprfx into unpredicated movprfx when mask is all-true.
* Allow zero falseOp to be contained when mask is not all-true.
* Fix Sve HWIntrin tests ConditionalSelect ZeroOp. The zero vector needs
to be passed directly as constant such that the falseOp->IsVectorZero
branch can be tested.
* Fix LSRA delay free to allow unary embedded masked ops to use movprfx.
@github-actionsgithub-actionsBot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Apr 20, 2026
@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Apr 20, 2026
@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.

@ylpoonlg

Copy link
Copy Markdown
ContributorAuthor

Example SPMI asmdiffs:

@@ -22,11 +22,11 @@
movz x0, #0xD1FFAB1E // data for <unknown class>:<unknown field>
movk x0, #0xD1FFAB1E LSL #16
movk x0, #0xD1FFAB1E LSL #32
ldr q17, [x0]
ptrue p0.d
- movprfx z18.d, p0/z, z16.d+ movprfx z18, z16
fmla z18.d, p0/m, z17.d, z17.d
str q18, [x0]

Replaces predicated movprfx with unpredicated movprfx when predicate is true.

@@ -20,31 +20,30 @@
;; size=16 bbWeight=1 PerfScore 3.50
G_M32226_IG02: ; bbWeight=1, gcrefRegs=0000 {}, byrefRegs=0000 {}, byref
ldr q16, [fp, #0x20] // [V00 arg0]
ldr q17, [fp, #0x10] // [V01 arg1]
ptrue p0.b
- movprfx z16.b, p0/z, z16.b
smax z16.b, p0/m, z16.b, z17.b
mov v0.16b, v16.16b

Removes unnecessary movprfx when moving the same register and predicate is all-true.

@@ -195,14 +191,12 @@
blr x1 // code for <unknown method>
; gcrRegs -[x0]
ldp q1, q3, [x19, #0x30]
mov v2.16b, v3.16b
ptrue p0.d
- movi v0.4s, #0
movprfx z4, z1
faddp z4.d, p0/m, z4.d, z2.d
- sel z4.d, p0, z4.d, z0.d
mvni v0.4s, #0
mov x0, x19
; gcrRegs +[x0]
mov w1, #1
mov x2, x21

Removes unnecessary selects and contain zero vector when mask is all-true.

 ; gcrRegs -[x0]
ldr q0, [x19, #0x18]
ldr q1, [x19, #0x28]
ptrue p0.d
cmpne p0.d, p0/z, z0.d, #0
- movi v3.4s, #0+ movprfx z3.d, p0/z, z3.d
frintn z3.d, p0/m, z1.d
movi v2.4s, #0
mov x0, x19
; gcrRegs +[x0]
mov w1, #1

Contains the zero vector and use zeroing movprfx.

@@ -150,13 +150,14 @@
ptrue p0.s
cmpne p0.s, p0/z, z8.s, #0
movi v16.4s, #0
mov z12.d, z9.d
fcvtnt z12.s, p0/m, z10.d
+ sel z12.s, p0, z12.s, z16.s
str q12, [fp, #0x20] // [V07 tmp6]
b G_M36822_IG05

Fixes a bug with inactive lanes for ConvertToSingleOdd. This was revealed by the changes to the test templates.

@ylpoonlg
ylpoonlg marked this pull request as ready for review April 23, 2026 16:28
@ylpoonlg

Copy link
Copy Markdown
ContributorAuthor

jitstressregs passes locally.

@dotnet/arm64-contrib @a74nh@dhartglassMSFT

@ylpoonlg

Copy link
Copy Markdown
ContributorAuthor

error : (NETCORE_ENGINEERING_TELEMETRY=Test) Test JIT/opt/SVE/ConstantMasks/ConstantMasks.cmd has failed.

Some optimization tests are failing, I will look into them further.

Comment threadsrc/coreclr/jit/lsraarm64.cpp
Comment threadsrc/coreclr/jit/lsraarm64.cpp
Comment threadsrc/coreclr/jit/hwintrinsiccodegenarm64.cpp Outdated
Comment threadsrc/coreclr/jit/hwintrinsiccodegenarm64.cpp Outdated
@ylpoonlg

Copy link
Copy Markdown
ContributorAuthor

There is still a failing SVE opt test ConstantMasks:

 552: G_M15649_IG02:
553: ptrue p0.s
554: abs z16.s, p0/m, z0.s
555: mov v0.16b, v16.16b
556: movz x0, #0xD1FFAB1E // code for ConstantMasks:Consume[System.Numerics.Vector`1[int]](System.Numerics.Vector`1[int])
next:179 !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: match on wrong line

The LSRA change caused an extra mov v0.16b, v16.16b, but I have not been able to prioritize the destination register over op1 (any ideas would be appreciated). This was done to allow for movprfx usage, but in this case the ptrue suppressed it, so it doesn't really need to be delayed free. Maybe I should revert to using SVE mov instead of movprfx for now, and leave this for #107134.

@dhartglassMSFT

Copy link
Copy Markdown
Contributor

There is still a failing SVE opt test ConstantMasks:

 552: G_M15649_IG02:
553: ptrue p0.s
554: abs z16.s, p0/m, z0.s
555: mov v0.16b, v16.16b
556: movz x0, #0xD1FFAB1E // code for ConstantMasks:Consume[System.Numerics.Vector`1[int]](System.Numerics.Vector`1[int])
next:179 !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: match on wrong line

The LSRA change caused an extra mov v0.16b, v16.16b, but I have not been able to prioritize the destination register over op1 (any ideas would be appreciated). This was done to allow for movprfx usage, but in this case the ptrue suppressed it, so it doesn't really need to be delayed free. Maybe I should revert to using SVE mov instead of movprfx for now, and leave this for #107134.

Hey @ylpoonlg@a74nh following up on this. I may have lost some context, but during lsra we know whether the mask is all true, correct? In any case let me know if you needed further follow-up here, sorry for the delay

@ylpoonlg

Copy link
Copy Markdown
ContributorAuthor

There is still a failing SVE opt test ConstantMasks:

 552: G_M15649_IG02:
553: ptrue p0.s
554: abs z16.s, p0/m, z0.s
555: mov v0.16b, v16.16b
556: movz x0, #0xD1FFAB1E // code for ConstantMasks:Consume[System.Numerics.Vector`1[int]](System.Numerics.Vector`1[int])
next:179 !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: match on wrong line

The LSRA change caused an extra mov v0.16b, v16.16b, but I have not been able to prioritize the destination register over op1 (any ideas would be appreciated). This was done to allow for movprfx usage, but in this case the ptrue suppressed it, so it doesn't really need to be delayed free. Maybe I should revert to using SVE mov instead of movprfx for now, and leave this for #107134.

Hey @ylpoonlg@a74nh following up on this. I may have lost some context, but during lsra we know whether the mask is all true, correct? In any case let me know if you needed further follow-up here, sorry for the delay

Thanks for looking at this. I think currently lsra is delay-freeing operands for all RMW instructions(#107134), but this is fine for now. The main issue here is the unary embedded masked operations, since they are not RMW but also support MOVPRFX. I attempted to enable its usage by allowing delay free in lsra, but looks like it is not assigning the registers optimally, causing the test failure:
For example with

abs z16.s, p0/m, z0.s
mov v0.16b, v16.16b

the extra mov is unnecessary if it can use the destination register directly and use a different source register:

abs z0.s, p0/m, z16.s

If this lsra is too complicated to fix in this PR, I can remove this particular optimization and not use MOVPRFX with unary embedded masked operations for now.

@a74nh

Copy link
Copy Markdown
Contributor

@ylpoonlg : I've taken a look at this and made some fixes in LSRA, which fix up the regressions in both Abs and ConvertToSingleOdd. I don't have the permissions to push directly to this PR, so could you please take a look at my two commits and add them into this PR (assuming you're happy with the changes 😄 ).

https://github.com/dotnet/runtime/compare/main...a74nh:runtime:github-movprfx_refactor_3?expand=1

@a74nha74nh mentioned this pull request Jun 24, 2026
20 tasks
@dhartglassMSFT

Copy link
Copy Markdown
Contributor

/azp run runtime-coreclr jitstressregs

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@dhartglassMSFT

Copy link
Copy Markdown
Contributor

/azp run runtime-coreclr jitstressregs

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@dhartglassMSFT

Copy link
Copy Markdown
Contributor

last regstress hit a known issue, kicking off a new one

@a74nh

Copy link
Copy Markdown
Contributor

@dhartglassMSFT - did something go wrong with the stress run again?

@dhartglassMSFT

Copy link
Copy Markdown
Contributor

/azp run runtime-coreclr jitstressregs

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@dhartglassMSFT

Copy link
Copy Markdown
Contributor

@dhartglassMSFT - did something go wrong with the stress run again?

It will surely work on the third try

@dhartglassMSFT

Copy link
Copy Markdown
Contributor

@a74nh I took another look, unfortunately the SPMI failures appear related.

[01:51:17] ISSUE: <ASSERT> #61471 D:\a\_work\1\s\src\coreclr\jit\hwintrinsiccodegenarm64.cpp (824) - Assertion failed '(targetReg != intrin.op2->GetRegNum()) || genIsSameLocalVar(rmwOp, intrin.op2)' in 'SveBenchmarks.ComplexMultiply:SveComplexMultiply():this' during 'Generate code' (IL size 514; hash 0xcf12aa28; FullOpts)

@dhartglassMSFT

dhartglassMSFT commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

@a74nh I had missed there were also these two in the SPMI output.

This now should be al the failures, apologies for missing these on my first glance yesterday
(same assert twice)

[17:22:24] ISSUE: <ASM_DIFF> main method 15075 of size 301 differs
[17:22:24] ISSUE: <ASM_DIFF> main method 18555 of size 535 differs
[17:22:24] ISSUE: <ASSERT> #21871 D:\a\_work\1\s\src\coreclr\jit\hwintrinsiccodegenarm64.cpp (854) - Assertion failed 'canRepairTargetOverlap || (targetReg != intrin.op2->GetRegNum()) || genIsSameLocalVar(rmwOp, intrin.op2)' in 'SveBenchmarks.ComplexMultiply:SveComplexMultiply():this' during 'Generate code' (IL size 514; hash 0xcf12aa28; FullOpts)
[17:22:24] [17:22:24] ISSUE: <ASM_DIFF> main method 11328 of size 148 differs
[17:22:24] ISSUE: <ASSERT> #17808 D:\a\_work\1\s\src\coreclr\jit\hwintrinsiccodegenarm64.cpp (854) - Assertion failed 'canRepairTargetOverlap || (targetReg != intrin.op2->GetRegNum()) || genIsSameLocalVar(rmwOp, intrin.op2)' in 'SveBenchmarks.Logarithm:SveLogarithm():this' during 'Generate code' (IL size 666; hash 0xfd45ed08; FullOpts)
[17:22:24] [17:22:24] Compilation failures

@a74nh

Copy link
Copy Markdown
Contributor

@a74nh I had missed there were also these two in the SPMI output.

This now should be al the failures, apologies for missing these on my first glance yesterday (same assert twice)

[17:22:24] ISSUE: <ASM_DIFF> main method 15075 of size 301 differs
[17:22:24] ISSUE: <ASM_DIFF> main method 18555 of size 535 differs
[17:22:24] ISSUE: <ASSERT> #21871 D:\a\_work\1\s\src\coreclr\jit\hwintrinsiccodegenarm64.cpp (854) - Assertion failed 'canRepairTargetOverlap || (targetReg != intrin.op2->GetRegNum()) || genIsSameLocalVar(rmwOp, intrin.op2)' in 'SveBenchmarks.ComplexMultiply:SveComplexMultiply():this' during 'Generate code' (IL size 514; hash 0xcf12aa28; FullOpts)
[17:22:24] [17:22:24] ISSUE: <ASM_DIFF> main method 11328 of size 148 differs
[17:22:24] ISSUE: <ASSERT> #17808 D:\a\_work\1\s\src\coreclr\jit\hwintrinsiccodegenarm64.cpp (854) - Assertion failed 'canRepairTargetOverlap || (targetReg != intrin.op2->GetRegNum()) || genIsSameLocalVar(rmwOp, intrin.op2)' in 'SveBenchmarks.Logarithm:SveLogarithm():this' during 'Generate code' (IL size 666; hash 0xfd45ed08; FullOpts)
[17:22:24] [17:22:24] Compilation failures

These should be fixed now too...

@dhartglassMSFT
dhartglassMSFT enabled auto-merge (squash) June 30, 2026 19:12
@dhartglassMSFT
dhartglassMSFT merged commit 411b771 into dotnet:mainJun 30, 2026
145 of 150 checks passed
@dhartglassMSFT

Copy link
Copy Markdown
Contributor

I merged this, thanks @a74nh and @ylpoon-arm for the fix here!

@dotnet-milestone-botdotnet-milestone-botBot added this to the 11.0-preview7 milestone Jul 1, 2026
@JulieLeeMSFTJulieLeeMSFT added the arm-sve Work related to arm64 SVE/SVE2 support label Jul 1, 2026
eiriktsarpalis pushed a commit that referenced this pull request Jul 15, 2026
This PR is the last part for #115508, with the following changes:
* Cleanup to `hwintrinsiccodegenarm64.cpp`:
* Move the embedded masked block to a new function
`genEmbeddedMaskedHWIntrinsic`.
* Combine codepaths for different number of operand cases and centralize
movprfx logic.
* Optimizations to movprfx usage in embedded masked operation codegen:
* Replace predicated movprfx with unpredicated movprfx when mask is
all-true. Unpredicated movprfx is generally preferred due to
performance.
* Allow zero falseOp to be contained when mask is not all-true so that
zeroing predicated movprfx can be used.
* Allow unary embedded masked ops to use movprfx. Unary embedded masked
ops are not RMW instructions, but may also support movprfx, which
require the target register to be delayed free in LSRA.
* Fixing the Sve HardwareIntrinsics tests `ConditionalSelect_ZeroOp`
calls: The `falseOp->IsVectorZero` branch in the codegen was previously
untested because the zero vector was passed as a local variable rather
than a constant vector. The zero vector needs to be passed directly into
the `ConditionalSelect` intrinsic in the test templates.
---------
Co-authored-by: Alan Hayward <alan.hayward@arm.com>
Co-authored-by: Yat Long Poon <yatlong.poon@arm.com>
Co-authored-by: dhartglassMSFT <dhartglass+github@microsoft.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Aug 1, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMIarm-sveWork related to arm64 SVE/SVE2 supportcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@ylpoonlg@dhartglassMSFT@a74nh@JulieLeeMSFT@ylpoon-arm
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' arm64: Clean up SVE embedded masked codegen by ylpoonlg · Pull Request #127164 · dotnet/runtime · GitHub
Skip to content

arm64: Clean up SVE embedded masked codegen - #127164

Merged
dhartglassMSFT merged 12 commits into
dotnet:mainfrom
ylpoonlg:github-movprfx_refactor_3
Jun 30, 2026
Merged

arm64: Clean up SVE embedded masked codegen#127164
dhartglassMSFT merged 12 commits into
dotnet:mainfrom
ylpoonlg:github-movprfx_refactor_3

Conversation

@ylpoonlg

Copy link
Copy Markdown
Contributor

This PR is the last part for #115508, with the following changes:

  • Cleanup to hwintrinsiccodegenarm64.cpp:

    • Move the embedded masked block to a new function genEmbeddedMaskedHWIntrinsic.
    • Combine codepaths for different number of operand cases and centralize movprfx logic.
  • Optimizations to movprfx usage in embedded masked operation codegen:

    • Replace predicated movprfx with unpredicated movprfx when mask is all-true. Unpredicated movprfx is generally preferred due to performance.
    • Allow zero falseOp to be contained when mask is not all-true so that zeroing predicated movprfx can be used.
    • Allow unary embedded masked ops to use movprfx. Unary embedded masked ops are not RMW instructions, but may also support movprfx, which require the target register to be delayed free in LSRA.
  • Fixing the Sve HardwareIntrinsics tests ConditionalSelect_ZeroOp calls: The falseOp->IsVectorZero branch in the codegen was previously untested because the zero vector was passed as a local variable rather than a constant vector. The zero vector needs to be passed directly into the ConditionalSelect intrinsic in the test templates.

* Move the embedded masked block to a new function.
* Combine codepaths for different number of operand cases.
* Optimise predicated movprfx into unpredicated movprfx when mask is all-true.
* Allow zero falseOp to be contained when mask is not all-true.
* Fix Sve HWIntrin tests ConditionalSelect ZeroOp. The zero vector needs
to be passed directly as constant such that the falseOp->IsVectorZero
branch can be tested.
* Fix LSRA delay free to allow unary embedded masked ops to use movprfx.
@github-actionsgithub-actionsBot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Apr 20, 2026
@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Apr 20, 2026
@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.

@ylpoonlg

Copy link
Copy Markdown
ContributorAuthor

Example SPMI asmdiffs:

@@ -22,11 +22,11 @@
movz x0, #0xD1FFAB1E // data for <unknown class>:<unknown field>
movk x0, #0xD1FFAB1E LSL #16
movk x0, #0xD1FFAB1E LSL #32
ldr q17, [x0]
ptrue p0.d
- movprfx z18.d, p0/z, z16.d+ movprfx z18, z16
fmla z18.d, p0/m, z17.d, z17.d
str q18, [x0]

Replaces predicated movprfx with unpredicated movprfx when predicate is true.

@@ -20,31 +20,30 @@
;; size=16 bbWeight=1 PerfScore 3.50
G_M32226_IG02: ; bbWeight=1, gcrefRegs=0000 {}, byrefRegs=0000 {}, byref
ldr q16, [fp, #0x20] // [V00 arg0]
ldr q17, [fp, #0x10] // [V01 arg1]
ptrue p0.b
- movprfx z16.b, p0/z, z16.b
smax z16.b, p0/m, z16.b, z17.b
mov v0.16b, v16.16b

Removes unnecessary movprfx when moving the same register and predicate is all-true.

@@ -195,14 +191,12 @@
blr x1 // code for <unknown method>
; gcrRegs -[x0]
ldp q1, q3, [x19, #0x30]
mov v2.16b, v3.16b
ptrue p0.d
- movi v0.4s, #0
movprfx z4, z1
faddp z4.d, p0/m, z4.d, z2.d
- sel z4.d, p0, z4.d, z0.d
mvni v0.4s, #0
mov x0, x19
; gcrRegs +[x0]
mov w1, #1
mov x2, x21

Removes unnecessary selects and contain zero vector when mask is all-true.

 ; gcrRegs -[x0]
ldr q0, [x19, #0x18]
ldr q1, [x19, #0x28]
ptrue p0.d
cmpne p0.d, p0/z, z0.d, #0
- movi v3.4s, #0+ movprfx z3.d, p0/z, z3.d
frintn z3.d, p0/m, z1.d
movi v2.4s, #0
mov x0, x19
; gcrRegs +[x0]
mov w1, #1

Contains the zero vector and use zeroing movprfx.

@@ -150,13 +150,14 @@
ptrue p0.s
cmpne p0.s, p0/z, z8.s, #0
movi v16.4s, #0
mov z12.d, z9.d
fcvtnt z12.s, p0/m, z10.d
+ sel z12.s, p0, z12.s, z16.s
str q12, [fp, #0x20] // [V07 tmp6]
b G_M36822_IG05

Fixes a bug with inactive lanes for ConvertToSingleOdd. This was revealed by the changes to the test templates.

@ylpoonlg
ylpoonlg marked this pull request as ready for review April 23, 2026 16:28
@ylpoonlg

Copy link
Copy Markdown
ContributorAuthor

jitstressregs passes locally.

@dotnet/arm64-contrib @a74nh@dhartglassMSFT

@ylpoonlg

Copy link
Copy Markdown
ContributorAuthor

error : (NETCORE_ENGINEERING_TELEMETRY=Test) Test JIT/opt/SVE/ConstantMasks/ConstantMasks.cmd has failed.

Some optimization tests are failing, I will look into them further.

Comment threadsrc/coreclr/jit/lsraarm64.cpp
Comment threadsrc/coreclr/jit/lsraarm64.cpp
Comment threadsrc/coreclr/jit/hwintrinsiccodegenarm64.cpp Outdated
Comment threadsrc/coreclr/jit/hwintrinsiccodegenarm64.cpp Outdated
@ylpoonlg

Copy link
Copy Markdown
ContributorAuthor

There is still a failing SVE opt test ConstantMasks:

 552: G_M15649_IG02:
553: ptrue p0.s
554: abs z16.s, p0/m, z0.s
555: mov v0.16b, v16.16b
556: movz x0, #0xD1FFAB1E // code for ConstantMasks:Consume[System.Numerics.Vector`1[int]](System.Numerics.Vector`1[int])
next:179 !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: match on wrong line

The LSRA change caused an extra mov v0.16b, v16.16b, but I have not been able to prioritize the destination register over op1 (any ideas would be appreciated). This was done to allow for movprfx usage, but in this case the ptrue suppressed it, so it doesn't really need to be delayed free. Maybe I should revert to using SVE mov instead of movprfx for now, and leave this for #107134.

@dhartglassMSFT

Copy link
Copy Markdown
Contributor

There is still a failing SVE opt test ConstantMasks:

 552: G_M15649_IG02:
553: ptrue p0.s
554: abs z16.s, p0/m, z0.s
555: mov v0.16b, v16.16b
556: movz x0, #0xD1FFAB1E // code for ConstantMasks:Consume[System.Numerics.Vector`1[int]](System.Numerics.Vector`1[int])
next:179 !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: match on wrong line

The LSRA change caused an extra mov v0.16b, v16.16b, but I have not been able to prioritize the destination register over op1 (any ideas would be appreciated). This was done to allow for movprfx usage, but in this case the ptrue suppressed it, so it doesn't really need to be delayed free. Maybe I should revert to using SVE mov instead of movprfx for now, and leave this for #107134.

Hey @ylpoonlg@a74nh following up on this. I may have lost some context, but during lsra we know whether the mask is all true, correct? In any case let me know if you needed further follow-up here, sorry for the delay

@ylpoonlg

Copy link
Copy Markdown
ContributorAuthor

There is still a failing SVE opt test ConstantMasks:

 552: G_M15649_IG02:
553: ptrue p0.s
554: abs z16.s, p0/m, z0.s
555: mov v0.16b, v16.16b
556: movz x0, #0xD1FFAB1E // code for ConstantMasks:Consume[System.Numerics.Vector`1[int]](System.Numerics.Vector`1[int])
next:179 !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: match on wrong line

The LSRA change caused an extra mov v0.16b, v16.16b, but I have not been able to prioritize the destination register over op1 (any ideas would be appreciated). This was done to allow for movprfx usage, but in this case the ptrue suppressed it, so it doesn't really need to be delayed free. Maybe I should revert to using SVE mov instead of movprfx for now, and leave this for #107134.

Hey @ylpoonlg@a74nh following up on this. I may have lost some context, but during lsra we know whether the mask is all true, correct? In any case let me know if you needed further follow-up here, sorry for the delay

Thanks for looking at this. I think currently lsra is delay-freeing operands for all RMW instructions(#107134), but this is fine for now. The main issue here is the unary embedded masked operations, since they are not RMW but also support MOVPRFX. I attempted to enable its usage by allowing delay free in lsra, but looks like it is not assigning the registers optimally, causing the test failure:
For example with

abs z16.s, p0/m, z0.s
mov v0.16b, v16.16b

the extra mov is unnecessary if it can use the destination register directly and use a different source register:

abs z0.s, p0/m, z16.s

If this lsra is too complicated to fix in this PR, I can remove this particular optimization and not use MOVPRFX with unary embedded masked operations for now.

@a74nh

Copy link
Copy Markdown
Contributor

@ylpoonlg : I've taken a look at this and made some fixes in LSRA, which fix up the regressions in both Abs and ConvertToSingleOdd. I don't have the permissions to push directly to this PR, so could you please take a look at my two commits and add them into this PR (assuming you're happy with the changes 😄 ).

https://github.com/dotnet/runtime/compare/main...a74nh:runtime:github-movprfx_refactor_3?expand=1

@a74nha74nh mentioned this pull request Jun 24, 2026
20 tasks
@dhartglassMSFT

Copy link
Copy Markdown
Contributor

/azp run runtime-coreclr jitstressregs

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@dhartglassMSFT

Copy link
Copy Markdown
Contributor

/azp run runtime-coreclr jitstressregs

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@dhartglassMSFT

Copy link
Copy Markdown
Contributor

last regstress hit a known issue, kicking off a new one

@a74nh

Copy link
Copy Markdown
Contributor

@dhartglassMSFT - did something go wrong with the stress run again?

@dhartglassMSFT

Copy link
Copy Markdown
Contributor

/azp run runtime-coreclr jitstressregs

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@dhartglassMSFT

Copy link
Copy Markdown
Contributor

@dhartglassMSFT - did something go wrong with the stress run again?

It will surely work on the third try

@dhartglassMSFT

Copy link
Copy Markdown
Contributor

@a74nh I took another look, unfortunately the SPMI failures appear related.

[01:51:17] ISSUE: <ASSERT> #61471 D:\a\_work\1\s\src\coreclr\jit\hwintrinsiccodegenarm64.cpp (824) - Assertion failed '(targetReg != intrin.op2->GetRegNum()) || genIsSameLocalVar(rmwOp, intrin.op2)' in 'SveBenchmarks.ComplexMultiply:SveComplexMultiply():this' during 'Generate code' (IL size 514; hash 0xcf12aa28; FullOpts)

@dhartglassMSFT

dhartglassMSFT commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

@a74nh I had missed there were also these two in the SPMI output.

This now should be al the failures, apologies for missing these on my first glance yesterday
(same assert twice)

[17:22:24] ISSUE: <ASM_DIFF> main method 15075 of size 301 differs
[17:22:24] ISSUE: <ASM_DIFF> main method 18555 of size 535 differs
[17:22:24] ISSUE: <ASSERT> #21871 D:\a\_work\1\s\src\coreclr\jit\hwintrinsiccodegenarm64.cpp (854) - Assertion failed 'canRepairTargetOverlap || (targetReg != intrin.op2->GetRegNum()) || genIsSameLocalVar(rmwOp, intrin.op2)' in 'SveBenchmarks.ComplexMultiply:SveComplexMultiply():this' during 'Generate code' (IL size 514; hash 0xcf12aa28; FullOpts)
[17:22:24] [17:22:24] ISSUE: <ASM_DIFF> main method 11328 of size 148 differs
[17:22:24] ISSUE: <ASSERT> #17808 D:\a\_work\1\s\src\coreclr\jit\hwintrinsiccodegenarm64.cpp (854) - Assertion failed 'canRepairTargetOverlap || (targetReg != intrin.op2->GetRegNum()) || genIsSameLocalVar(rmwOp, intrin.op2)' in 'SveBenchmarks.Logarithm:SveLogarithm():this' during 'Generate code' (IL size 666; hash 0xfd45ed08; FullOpts)
[17:22:24] [17:22:24] Compilation failures

@a74nh

Copy link
Copy Markdown
Contributor

@a74nh I had missed there were also these two in the SPMI output.

This now should be al the failures, apologies for missing these on my first glance yesterday (same assert twice)

[17:22:24] ISSUE: <ASM_DIFF> main method 15075 of size 301 differs
[17:22:24] ISSUE: <ASM_DIFF> main method 18555 of size 535 differs
[17:22:24] ISSUE: <ASSERT> #21871 D:\a\_work\1\s\src\coreclr\jit\hwintrinsiccodegenarm64.cpp (854) - Assertion failed 'canRepairTargetOverlap || (targetReg != intrin.op2->GetRegNum()) || genIsSameLocalVar(rmwOp, intrin.op2)' in 'SveBenchmarks.ComplexMultiply:SveComplexMultiply():this' during 'Generate code' (IL size 514; hash 0xcf12aa28; FullOpts)
[17:22:24] [17:22:24] ISSUE: <ASM_DIFF> main method 11328 of size 148 differs
[17:22:24] ISSUE: <ASSERT> #17808 D:\a\_work\1\s\src\coreclr\jit\hwintrinsiccodegenarm64.cpp (854) - Assertion failed 'canRepairTargetOverlap || (targetReg != intrin.op2->GetRegNum()) || genIsSameLocalVar(rmwOp, intrin.op2)' in 'SveBenchmarks.Logarithm:SveLogarithm():this' during 'Generate code' (IL size 666; hash 0xfd45ed08; FullOpts)
[17:22:24] [17:22:24] Compilation failures

These should be fixed now too...

@dhartglassMSFT
dhartglassMSFT enabled auto-merge (squash) June 30, 2026 19:12
@dhartglassMSFT
dhartglassMSFT merged commit 411b771 into dotnet:mainJun 30, 2026
145 of 150 checks passed
@dhartglassMSFT

Copy link
Copy Markdown
Contributor

I merged this, thanks @a74nh and @ylpoon-arm for the fix here!

@dotnet-milestone-botdotnet-milestone-botBot added this to the 11.0-preview7 milestone Jul 1, 2026
@JulieLeeMSFTJulieLeeMSFT added the arm-sve Work related to arm64 SVE/SVE2 support label Jul 1, 2026
eiriktsarpalis pushed a commit that referenced this pull request Jul 15, 2026
This PR is the last part for #115508, with the following changes:
* Cleanup to `hwintrinsiccodegenarm64.cpp`:
* Move the embedded masked block to a new function
`genEmbeddedMaskedHWIntrinsic`.
* Combine codepaths for different number of operand cases and centralize
movprfx logic.
* Optimizations to movprfx usage in embedded masked operation codegen:
* Replace predicated movprfx with unpredicated movprfx when mask is
all-true. Unpredicated movprfx is generally preferred due to
performance.
* Allow zero falseOp to be contained when mask is not all-true so that
zeroing predicated movprfx can be used.
* Allow unary embedded masked ops to use movprfx. Unary embedded masked
ops are not RMW instructions, but may also support movprfx, which
require the target register to be delayed free in LSRA.
* Fixing the Sve HardwareIntrinsics tests `ConditionalSelect_ZeroOp`
calls: The `falseOp->IsVectorZero` branch in the codegen was previously
untested because the zero vector was passed as a local variable rather
than a constant vector. The zero vector needs to be passed directly into
the `ConditionalSelect` intrinsic in the test templates.
---------
Co-authored-by: Alan Hayward <alan.hayward@arm.com>
Co-authored-by: Yat Long Poon <yatlong.poon@arm.com>
Co-authored-by: dhartglassMSFT <dhartglass+github@microsoft.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Aug 1, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMIarm-sveWork related to arm64 SVE/SVE2 supportcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@ylpoonlg@dhartglassMSFT@a74nh@JulieLeeMSFT@ylpoon-arm
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' arm64: Clean up SVE embedded masked codegen by ylpoonlg · Pull Request #127164 · dotnet/runtime · GitHub
Skip to content

arm64: Clean up SVE embedded masked codegen - #127164

Merged
dhartglassMSFT merged 12 commits into
dotnet:mainfrom
ylpoonlg:github-movprfx_refactor_3
Jun 30, 2026
Merged

arm64: Clean up SVE embedded masked codegen#127164
dhartglassMSFT merged 12 commits into
dotnet:mainfrom
ylpoonlg:github-movprfx_refactor_3

Conversation

@ylpoonlg

Copy link
Copy Markdown
Contributor

This PR is the last part for #115508, with the following changes:

  • Cleanup to hwintrinsiccodegenarm64.cpp:

    • Move the embedded masked block to a new function genEmbeddedMaskedHWIntrinsic.
    • Combine codepaths for different number of operand cases and centralize movprfx logic.
  • Optimizations to movprfx usage in embedded masked operation codegen:

    • Replace predicated movprfx with unpredicated movprfx when mask is all-true. Unpredicated movprfx is generally preferred due to performance.
    • Allow zero falseOp to be contained when mask is not all-true so that zeroing predicated movprfx can be used.
    • Allow unary embedded masked ops to use movprfx. Unary embedded masked ops are not RMW instructions, but may also support movprfx, which require the target register to be delayed free in LSRA.
  • Fixing the Sve HardwareIntrinsics tests ConditionalSelect_ZeroOp calls: The falseOp->IsVectorZero branch in the codegen was previously untested because the zero vector was passed as a local variable rather than a constant vector. The zero vector needs to be passed directly into the ConditionalSelect intrinsic in the test templates.

* Move the embedded masked block to a new function.
* Combine codepaths for different number of operand cases.
* Optimise predicated movprfx into unpredicated movprfx when mask is all-true.
* Allow zero falseOp to be contained when mask is not all-true.
* Fix Sve HWIntrin tests ConditionalSelect ZeroOp. The zero vector needs
to be passed directly as constant such that the falseOp->IsVectorZero
branch can be tested.
* Fix LSRA delay free to allow unary embedded masked ops to use movprfx.
@github-actionsgithub-actionsBot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Apr 20, 2026
@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Apr 20, 2026
@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.

@ylpoonlg

Copy link
Copy Markdown
ContributorAuthor

Example SPMI asmdiffs:

@@ -22,11 +22,11 @@
movz x0, #0xD1FFAB1E // data for <unknown class>:<unknown field>
movk x0, #0xD1FFAB1E LSL #16
movk x0, #0xD1FFAB1E LSL #32
ldr q17, [x0]
ptrue p0.d
- movprfx z18.d, p0/z, z16.d+ movprfx z18, z16
fmla z18.d, p0/m, z17.d, z17.d
str q18, [x0]

Replaces predicated movprfx with unpredicated movprfx when predicate is true.

@@ -20,31 +20,30 @@
;; size=16 bbWeight=1 PerfScore 3.50
G_M32226_IG02: ; bbWeight=1, gcrefRegs=0000 {}, byrefRegs=0000 {}, byref
ldr q16, [fp, #0x20] // [V00 arg0]
ldr q17, [fp, #0x10] // [V01 arg1]
ptrue p0.b
- movprfx z16.b, p0/z, z16.b
smax z16.b, p0/m, z16.b, z17.b
mov v0.16b, v16.16b

Removes unnecessary movprfx when moving the same register and predicate is all-true.

@@ -195,14 +191,12 @@
blr x1 // code for <unknown method>
; gcrRegs -[x0]
ldp q1, q3, [x19, #0x30]
mov v2.16b, v3.16b
ptrue p0.d
- movi v0.4s, #0
movprfx z4, z1
faddp z4.d, p0/m, z4.d, z2.d
- sel z4.d, p0, z4.d, z0.d
mvni v0.4s, #0
mov x0, x19
; gcrRegs +[x0]
mov w1, #1
mov x2, x21

Removes unnecessary selects and contain zero vector when mask is all-true.

 ; gcrRegs -[x0]
ldr q0, [x19, #0x18]
ldr q1, [x19, #0x28]
ptrue p0.d
cmpne p0.d, p0/z, z0.d, #0
- movi v3.4s, #0+ movprfx z3.d, p0/z, z3.d
frintn z3.d, p0/m, z1.d
movi v2.4s, #0
mov x0, x19
; gcrRegs +[x0]
mov w1, #1

Contains the zero vector and use zeroing movprfx.

@@ -150,13 +150,14 @@
ptrue p0.s
cmpne p0.s, p0/z, z8.s, #0
movi v16.4s, #0
mov z12.d, z9.d
fcvtnt z12.s, p0/m, z10.d
+ sel z12.s, p0, z12.s, z16.s
str q12, [fp, #0x20] // [V07 tmp6]
b G_M36822_IG05

Fixes a bug with inactive lanes for ConvertToSingleOdd. This was revealed by the changes to the test templates.

@ylpoonlg
ylpoonlg marked this pull request as ready for review April 23, 2026 16:28
@ylpoonlg

Copy link
Copy Markdown
ContributorAuthor

jitstressregs passes locally.

@dotnet/arm64-contrib @a74nh@dhartglassMSFT

@ylpoonlg

Copy link
Copy Markdown
ContributorAuthor

error : (NETCORE_ENGINEERING_TELEMETRY=Test) Test JIT/opt/SVE/ConstantMasks/ConstantMasks.cmd has failed.

Some optimization tests are failing, I will look into them further.

Comment threadsrc/coreclr/jit/lsraarm64.cpp
Comment threadsrc/coreclr/jit/lsraarm64.cpp
Comment threadsrc/coreclr/jit/hwintrinsiccodegenarm64.cpp Outdated
Comment threadsrc/coreclr/jit/hwintrinsiccodegenarm64.cpp Outdated
@ylpoonlg

Copy link
Copy Markdown
ContributorAuthor

There is still a failing SVE opt test ConstantMasks:

 552: G_M15649_IG02:
553: ptrue p0.s
554: abs z16.s, p0/m, z0.s
555: mov v0.16b, v16.16b
556: movz x0, #0xD1FFAB1E // code for ConstantMasks:Consume[System.Numerics.Vector`1[int]](System.Numerics.Vector`1[int])
next:179 !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: match on wrong line

The LSRA change caused an extra mov v0.16b, v16.16b, but I have not been able to prioritize the destination register over op1 (any ideas would be appreciated). This was done to allow for movprfx usage, but in this case the ptrue suppressed it, so it doesn't really need to be delayed free. Maybe I should revert to using SVE mov instead of movprfx for now, and leave this for #107134.

@dhartglassMSFT

Copy link
Copy Markdown
Contributor

There is still a failing SVE opt test ConstantMasks:

 552: G_M15649_IG02:
553: ptrue p0.s
554: abs z16.s, p0/m, z0.s
555: mov v0.16b, v16.16b
556: movz x0, #0xD1FFAB1E // code for ConstantMasks:Consume[System.Numerics.Vector`1[int]](System.Numerics.Vector`1[int])
next:179 !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: match on wrong line

The LSRA change caused an extra mov v0.16b, v16.16b, but I have not been able to prioritize the destination register over op1 (any ideas would be appreciated). This was done to allow for movprfx usage, but in this case the ptrue suppressed it, so it doesn't really need to be delayed free. Maybe I should revert to using SVE mov instead of movprfx for now, and leave this for #107134.

Hey @ylpoonlg@a74nh following up on this. I may have lost some context, but during lsra we know whether the mask is all true, correct? In any case let me know if you needed further follow-up here, sorry for the delay

@ylpoonlg

Copy link
Copy Markdown
ContributorAuthor

There is still a failing SVE opt test ConstantMasks:

 552: G_M15649_IG02:
553: ptrue p0.s
554: abs z16.s, p0/m, z0.s
555: mov v0.16b, v16.16b
556: movz x0, #0xD1FFAB1E // code for ConstantMasks:Consume[System.Numerics.Vector`1[int]](System.Numerics.Vector`1[int])
next:179 !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: match on wrong line

The LSRA change caused an extra mov v0.16b, v16.16b, but I have not been able to prioritize the destination register over op1 (any ideas would be appreciated). This was done to allow for movprfx usage, but in this case the ptrue suppressed it, so it doesn't really need to be delayed free. Maybe I should revert to using SVE mov instead of movprfx for now, and leave this for #107134.

Hey @ylpoonlg@a74nh following up on this. I may have lost some context, but during lsra we know whether the mask is all true, correct? In any case let me know if you needed further follow-up here, sorry for the delay

Thanks for looking at this. I think currently lsra is delay-freeing operands for all RMW instructions(#107134), but this is fine for now. The main issue here is the unary embedded masked operations, since they are not RMW but also support MOVPRFX. I attempted to enable its usage by allowing delay free in lsra, but looks like it is not assigning the registers optimally, causing the test failure:
For example with

abs z16.s, p0/m, z0.s
mov v0.16b, v16.16b

the extra mov is unnecessary if it can use the destination register directly and use a different source register:

abs z0.s, p0/m, z16.s

If this lsra is too complicated to fix in this PR, I can remove this particular optimization and not use MOVPRFX with unary embedded masked operations for now.

@a74nh

Copy link
Copy Markdown
Contributor

@ylpoonlg : I've taken a look at this and made some fixes in LSRA, which fix up the regressions in both Abs and ConvertToSingleOdd. I don't have the permissions to push directly to this PR, so could you please take a look at my two commits and add them into this PR (assuming you're happy with the changes 😄 ).

https://github.com/dotnet/runtime/compare/main...a74nh:runtime:github-movprfx_refactor_3?expand=1

@a74nha74nh mentioned this pull request Jun 24, 2026
20 tasks
@dhartglassMSFT

Copy link
Copy Markdown
Contributor

/azp run runtime-coreclr jitstressregs

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@dhartglassMSFT

Copy link
Copy Markdown
Contributor

/azp run runtime-coreclr jitstressregs

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@dhartglassMSFT

Copy link
Copy Markdown
Contributor

last regstress hit a known issue, kicking off a new one

@a74nh

Copy link
Copy Markdown
Contributor

@dhartglassMSFT - did something go wrong with the stress run again?

@dhartglassMSFT

Copy link
Copy Markdown
Contributor

/azp run runtime-coreclr jitstressregs

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@dhartglassMSFT

Copy link
Copy Markdown
Contributor

@dhartglassMSFT - did something go wrong with the stress run again?

It will surely work on the third try

@dhartglassMSFT

Copy link
Copy Markdown
Contributor

@a74nh I took another look, unfortunately the SPMI failures appear related.

[01:51:17] ISSUE: <ASSERT> #61471 D:\a\_work\1\s\src\coreclr\jit\hwintrinsiccodegenarm64.cpp (824) - Assertion failed '(targetReg != intrin.op2->GetRegNum()) || genIsSameLocalVar(rmwOp, intrin.op2)' in 'SveBenchmarks.ComplexMultiply:SveComplexMultiply():this' during 'Generate code' (IL size 514; hash 0xcf12aa28; FullOpts)

@dhartglassMSFT

dhartglassMSFT commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

@a74nh I had missed there were also these two in the SPMI output.

This now should be al the failures, apologies for missing these on my first glance yesterday
(same assert twice)

[17:22:24] ISSUE: <ASM_DIFF> main method 15075 of size 301 differs
[17:22:24] ISSUE: <ASM_DIFF> main method 18555 of size 535 differs
[17:22:24] ISSUE: <ASSERT> #21871 D:\a\_work\1\s\src\coreclr\jit\hwintrinsiccodegenarm64.cpp (854) - Assertion failed 'canRepairTargetOverlap || (targetReg != intrin.op2->GetRegNum()) || genIsSameLocalVar(rmwOp, intrin.op2)' in 'SveBenchmarks.ComplexMultiply:SveComplexMultiply():this' during 'Generate code' (IL size 514; hash 0xcf12aa28; FullOpts)
[17:22:24] [17:22:24] ISSUE: <ASM_DIFF> main method 11328 of size 148 differs
[17:22:24] ISSUE: <ASSERT> #17808 D:\a\_work\1\s\src\coreclr\jit\hwintrinsiccodegenarm64.cpp (854) - Assertion failed 'canRepairTargetOverlap || (targetReg != intrin.op2->GetRegNum()) || genIsSameLocalVar(rmwOp, intrin.op2)' in 'SveBenchmarks.Logarithm:SveLogarithm():this' during 'Generate code' (IL size 666; hash 0xfd45ed08; FullOpts)
[17:22:24] [17:22:24] Compilation failures

@a74nh

Copy link
Copy Markdown
Contributor

@a74nh I had missed there were also these two in the SPMI output.

This now should be al the failures, apologies for missing these on my first glance yesterday (same assert twice)

[17:22:24] ISSUE: <ASM_DIFF> main method 15075 of size 301 differs
[17:22:24] ISSUE: <ASM_DIFF> main method 18555 of size 535 differs
[17:22:24] ISSUE: <ASSERT> #21871 D:\a\_work\1\s\src\coreclr\jit\hwintrinsiccodegenarm64.cpp (854) - Assertion failed 'canRepairTargetOverlap || (targetReg != intrin.op2->GetRegNum()) || genIsSameLocalVar(rmwOp, intrin.op2)' in 'SveBenchmarks.ComplexMultiply:SveComplexMultiply():this' during 'Generate code' (IL size 514; hash 0xcf12aa28; FullOpts)
[17:22:24] [17:22:24] ISSUE: <ASM_DIFF> main method 11328 of size 148 differs
[17:22:24] ISSUE: <ASSERT> #17808 D:\a\_work\1\s\src\coreclr\jit\hwintrinsiccodegenarm64.cpp (854) - Assertion failed 'canRepairTargetOverlap || (targetReg != intrin.op2->GetRegNum()) || genIsSameLocalVar(rmwOp, intrin.op2)' in 'SveBenchmarks.Logarithm:SveLogarithm():this' during 'Generate code' (IL size 666; hash 0xfd45ed08; FullOpts)
[17:22:24] [17:22:24] Compilation failures

These should be fixed now too...

@dhartglassMSFT
dhartglassMSFT enabled auto-merge (squash) June 30, 2026 19:12
@dhartglassMSFT
dhartglassMSFT merged commit 411b771 into dotnet:mainJun 30, 2026
145 of 150 checks passed
@dhartglassMSFT

Copy link
Copy Markdown
Contributor

I merged this, thanks @a74nh and @ylpoon-arm for the fix here!

@dotnet-milestone-botdotnet-milestone-botBot added this to the 11.0-preview7 milestone Jul 1, 2026
@JulieLeeMSFTJulieLeeMSFT added the arm-sve Work related to arm64 SVE/SVE2 support label Jul 1, 2026
eiriktsarpalis pushed a commit that referenced this pull request Jul 15, 2026
This PR is the last part for #115508, with the following changes:
* Cleanup to `hwintrinsiccodegenarm64.cpp`:
* Move the embedded masked block to a new function
`genEmbeddedMaskedHWIntrinsic`.
* Combine codepaths for different number of operand cases and centralize
movprfx logic.
* Optimizations to movprfx usage in embedded masked operation codegen:
* Replace predicated movprfx with unpredicated movprfx when mask is
all-true. Unpredicated movprfx is generally preferred due to
performance.
* Allow zero falseOp to be contained when mask is not all-true so that
zeroing predicated movprfx can be used.
* Allow unary embedded masked ops to use movprfx. Unary embedded masked
ops are not RMW instructions, but may also support movprfx, which
require the target register to be delayed free in LSRA.
* Fixing the Sve HardwareIntrinsics tests `ConditionalSelect_ZeroOp`
calls: The `falseOp->IsVectorZero` branch in the codegen was previously
untested because the zero vector was passed as a local variable rather
than a constant vector. The zero vector needs to be passed directly into
the `ConditionalSelect` intrinsic in the test templates.
---------
Co-authored-by: Alan Hayward <alan.hayward@arm.com>
Co-authored-by: Yat Long Poon <yatlong.poon@arm.com>
Co-authored-by: dhartglassMSFT <dhartglass+github@microsoft.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Aug 1, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMIarm-sveWork related to arm64 SVE/SVE2 supportcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@ylpoonlg@dhartglassMSFT@a74nh@JulieLeeMSFT@ylpoon-arm
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' arm64: Clean up SVE embedded masked codegen by ylpoonlg · Pull Request #127164 · dotnet/runtime · GitHub
Skip to content

arm64: Clean up SVE embedded masked codegen - #127164

Merged
dhartglassMSFT merged 12 commits into
dotnet:mainfrom
ylpoonlg:github-movprfx_refactor_3
Jun 30, 2026
Merged

arm64: Clean up SVE embedded masked codegen#127164
dhartglassMSFT merged 12 commits into
dotnet:mainfrom
ylpoonlg:github-movprfx_refactor_3

Conversation

@ylpoonlg

Copy link
Copy Markdown
Contributor

This PR is the last part for #115508, with the following changes:

  • Cleanup to hwintrinsiccodegenarm64.cpp:

    • Move the embedded masked block to a new function genEmbeddedMaskedHWIntrinsic.
    • Combine codepaths for different number of operand cases and centralize movprfx logic.
  • Optimizations to movprfx usage in embedded masked operation codegen:

    • Replace predicated movprfx with unpredicated movprfx when mask is all-true. Unpredicated movprfx is generally preferred due to performance.
    • Allow zero falseOp to be contained when mask is not all-true so that zeroing predicated movprfx can be used.
    • Allow unary embedded masked ops to use movprfx. Unary embedded masked ops are not RMW instructions, but may also support movprfx, which require the target register to be delayed free in LSRA.
  • Fixing the Sve HardwareIntrinsics tests ConditionalSelect_ZeroOp calls: The falseOp->IsVectorZero branch in the codegen was previously untested because the zero vector was passed as a local variable rather than a constant vector. The zero vector needs to be passed directly into the ConditionalSelect intrinsic in the test templates.

* Move the embedded masked block to a new function.
* Combine codepaths for different number of operand cases.
* Optimise predicated movprfx into unpredicated movprfx when mask is all-true.
* Allow zero falseOp to be contained when mask is not all-true.
* Fix Sve HWIntrin tests ConditionalSelect ZeroOp. The zero vector needs
to be passed directly as constant such that the falseOp->IsVectorZero
branch can be tested.
* Fix LSRA delay free to allow unary embedded masked ops to use movprfx.
@github-actionsgithub-actionsBot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Apr 20, 2026
@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Apr 20, 2026
@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.

@ylpoonlg

Copy link
Copy Markdown
ContributorAuthor

Example SPMI asmdiffs:

@@ -22,11 +22,11 @@
movz x0, #0xD1FFAB1E // data for <unknown class>:<unknown field>
movk x0, #0xD1FFAB1E LSL #16
movk x0, #0xD1FFAB1E LSL #32
ldr q17, [x0]
ptrue p0.d
- movprfx z18.d, p0/z, z16.d+ movprfx z18, z16
fmla z18.d, p0/m, z17.d, z17.d
str q18, [x0]

Replaces predicated movprfx with unpredicated movprfx when predicate is true.

@@ -20,31 +20,30 @@
;; size=16 bbWeight=1 PerfScore 3.50
G_M32226_IG02: ; bbWeight=1, gcrefRegs=0000 {}, byrefRegs=0000 {}, byref
ldr q16, [fp, #0x20] // [V00 arg0]
ldr q17, [fp, #0x10] // [V01 arg1]
ptrue p0.b
- movprfx z16.b, p0/z, z16.b
smax z16.b, p0/m, z16.b, z17.b
mov v0.16b, v16.16b

Removes unnecessary movprfx when moving the same register and predicate is all-true.

@@ -195,14 +191,12 @@
blr x1 // code for <unknown method>
; gcrRegs -[x0]
ldp q1, q3, [x19, #0x30]
mov v2.16b, v3.16b
ptrue p0.d
- movi v0.4s, #0
movprfx z4, z1
faddp z4.d, p0/m, z4.d, z2.d
- sel z4.d, p0, z4.d, z0.d
mvni v0.4s, #0
mov x0, x19
; gcrRegs +[x0]
mov w1, #1
mov x2, x21

Removes unnecessary selects and contain zero vector when mask is all-true.

 ; gcrRegs -[x0]
ldr q0, [x19, #0x18]
ldr q1, [x19, #0x28]
ptrue p0.d
cmpne p0.d, p0/z, z0.d, #0
- movi v3.4s, #0+ movprfx z3.d, p0/z, z3.d
frintn z3.d, p0/m, z1.d
movi v2.4s, #0
mov x0, x19
; gcrRegs +[x0]
mov w1, #1

Contains the zero vector and use zeroing movprfx.

@@ -150,13 +150,14 @@
ptrue p0.s
cmpne p0.s, p0/z, z8.s, #0
movi v16.4s, #0
mov z12.d, z9.d
fcvtnt z12.s, p0/m, z10.d
+ sel z12.s, p0, z12.s, z16.s
str q12, [fp, #0x20] // [V07 tmp6]
b G_M36822_IG05

Fixes a bug with inactive lanes for ConvertToSingleOdd. This was revealed by the changes to the test templates.

@ylpoonlg
ylpoonlg marked this pull request as ready for review April 23, 2026 16:28
@ylpoonlg

Copy link
Copy Markdown
ContributorAuthor

jitstressregs passes locally.

@dotnet/arm64-contrib @a74nh@dhartglassMSFT

@ylpoonlg

Copy link
Copy Markdown
ContributorAuthor

error : (NETCORE_ENGINEERING_TELEMETRY=Test) Test JIT/opt/SVE/ConstantMasks/ConstantMasks.cmd has failed.

Some optimization tests are failing, I will look into them further.

Comment threadsrc/coreclr/jit/lsraarm64.cpp
Comment threadsrc/coreclr/jit/lsraarm64.cpp
Comment threadsrc/coreclr/jit/hwintrinsiccodegenarm64.cpp Outdated
Comment threadsrc/coreclr/jit/hwintrinsiccodegenarm64.cpp Outdated
@ylpoonlg

Copy link
Copy Markdown
ContributorAuthor

There is still a failing SVE opt test ConstantMasks:

 552: G_M15649_IG02:
553: ptrue p0.s
554: abs z16.s, p0/m, z0.s
555: mov v0.16b, v16.16b
556: movz x0, #0xD1FFAB1E // code for ConstantMasks:Consume[System.Numerics.Vector`1[int]](System.Numerics.Vector`1[int])
next:179 !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: match on wrong line

The LSRA change caused an extra mov v0.16b, v16.16b, but I have not been able to prioritize the destination register over op1 (any ideas would be appreciated). This was done to allow for movprfx usage, but in this case the ptrue suppressed it, so it doesn't really need to be delayed free. Maybe I should revert to using SVE mov instead of movprfx for now, and leave this for #107134.

@dhartglassMSFT

Copy link
Copy Markdown
Contributor

There is still a failing SVE opt test ConstantMasks:

 552: G_M15649_IG02:
553: ptrue p0.s
554: abs z16.s, p0/m, z0.s
555: mov v0.16b, v16.16b
556: movz x0, #0xD1FFAB1E // code for ConstantMasks:Consume[System.Numerics.Vector`1[int]](System.Numerics.Vector`1[int])
next:179 !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: match on wrong line

The LSRA change caused an extra mov v0.16b, v16.16b, but I have not been able to prioritize the destination register over op1 (any ideas would be appreciated). This was done to allow for movprfx usage, but in this case the ptrue suppressed it, so it doesn't really need to be delayed free. Maybe I should revert to using SVE mov instead of movprfx for now, and leave this for #107134.

Hey @ylpoonlg@a74nh following up on this. I may have lost some context, but during lsra we know whether the mask is all true, correct? In any case let me know if you needed further follow-up here, sorry for the delay

@ylpoonlg

Copy link
Copy Markdown
ContributorAuthor

There is still a failing SVE opt test ConstantMasks:

 552: G_M15649_IG02:
553: ptrue p0.s
554: abs z16.s, p0/m, z0.s
555: mov v0.16b, v16.16b
556: movz x0, #0xD1FFAB1E // code for ConstantMasks:Consume[System.Numerics.Vector`1[int]](System.Numerics.Vector`1[int])
next:179 !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: match on wrong line

The LSRA change caused an extra mov v0.16b, v16.16b, but I have not been able to prioritize the destination register over op1 (any ideas would be appreciated). This was done to allow for movprfx usage, but in this case the ptrue suppressed it, so it doesn't really need to be delayed free. Maybe I should revert to using SVE mov instead of movprfx for now, and leave this for #107134.

Hey @ylpoonlg@a74nh following up on this. I may have lost some context, but during lsra we know whether the mask is all true, correct? In any case let me know if you needed further follow-up here, sorry for the delay

Thanks for looking at this. I think currently lsra is delay-freeing operands for all RMW instructions(#107134), but this is fine for now. The main issue here is the unary embedded masked operations, since they are not RMW but also support MOVPRFX. I attempted to enable its usage by allowing delay free in lsra, but looks like it is not assigning the registers optimally, causing the test failure:
For example with

abs z16.s, p0/m, z0.s
mov v0.16b, v16.16b

the extra mov is unnecessary if it can use the destination register directly and use a different source register:

abs z0.s, p0/m, z16.s

If this lsra is too complicated to fix in this PR, I can remove this particular optimization and not use MOVPRFX with unary embedded masked operations for now.

@a74nh

Copy link
Copy Markdown
Contributor

@ylpoonlg : I've taken a look at this and made some fixes in LSRA, which fix up the regressions in both Abs and ConvertToSingleOdd. I don't have the permissions to push directly to this PR, so could you please take a look at my two commits and add them into this PR (assuming you're happy with the changes 😄 ).

https://github.com/dotnet/runtime/compare/main...a74nh:runtime:github-movprfx_refactor_3?expand=1

@a74nha74nh mentioned this pull request Jun 24, 2026
20 tasks
@dhartglassMSFT

Copy link
Copy Markdown
Contributor

/azp run runtime-coreclr jitstressregs

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@dhartglassMSFT

Copy link
Copy Markdown
Contributor

/azp run runtime-coreclr jitstressregs

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@dhartglassMSFT

Copy link
Copy Markdown
Contributor

last regstress hit a known issue, kicking off a new one

@a74nh

Copy link
Copy Markdown
Contributor

@dhartglassMSFT - did something go wrong with the stress run again?

@dhartglassMSFT

Copy link
Copy Markdown
Contributor

/azp run runtime-coreclr jitstressregs

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@dhartglassMSFT

Copy link
Copy Markdown
Contributor

@dhartglassMSFT - did something go wrong with the stress run again?

It will surely work on the third try

@dhartglassMSFT

Copy link
Copy Markdown
Contributor

@a74nh I took another look, unfortunately the SPMI failures appear related.

[01:51:17] ISSUE: <ASSERT> #61471 D:\a\_work\1\s\src\coreclr\jit\hwintrinsiccodegenarm64.cpp (824) - Assertion failed '(targetReg != intrin.op2->GetRegNum()) || genIsSameLocalVar(rmwOp, intrin.op2)' in 'SveBenchmarks.ComplexMultiply:SveComplexMultiply():this' during 'Generate code' (IL size 514; hash 0xcf12aa28; FullOpts)

@dhartglassMSFT

dhartglassMSFT commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

@a74nh I had missed there were also these two in the SPMI output.

This now should be al the failures, apologies for missing these on my first glance yesterday
(same assert twice)

[17:22:24] ISSUE: <ASM_DIFF> main method 15075 of size 301 differs
[17:22:24] ISSUE: <ASM_DIFF> main method 18555 of size 535 differs
[17:22:24] ISSUE: <ASSERT> #21871 D:\a\_work\1\s\src\coreclr\jit\hwintrinsiccodegenarm64.cpp (854) - Assertion failed 'canRepairTargetOverlap || (targetReg != intrin.op2->GetRegNum()) || genIsSameLocalVar(rmwOp, intrin.op2)' in 'SveBenchmarks.ComplexMultiply:SveComplexMultiply():this' during 'Generate code' (IL size 514; hash 0xcf12aa28; FullOpts)
[17:22:24] [17:22:24] ISSUE: <ASM_DIFF> main method 11328 of size 148 differs
[17:22:24] ISSUE: <ASSERT> #17808 D:\a\_work\1\s\src\coreclr\jit\hwintrinsiccodegenarm64.cpp (854) - Assertion failed 'canRepairTargetOverlap || (targetReg != intrin.op2->GetRegNum()) || genIsSameLocalVar(rmwOp, intrin.op2)' in 'SveBenchmarks.Logarithm:SveLogarithm():this' during 'Generate code' (IL size 666; hash 0xfd45ed08; FullOpts)
[17:22:24] [17:22:24] Compilation failures

@a74nh

Copy link
Copy Markdown
Contributor

@a74nh I had missed there were also these two in the SPMI output.

This now should be al the failures, apologies for missing these on my first glance yesterday (same assert twice)

[17:22:24] ISSUE: <ASM_DIFF> main method 15075 of size 301 differs
[17:22:24] ISSUE: <ASM_DIFF> main method 18555 of size 535 differs
[17:22:24] ISSUE: <ASSERT> #21871 D:\a\_work\1\s\src\coreclr\jit\hwintrinsiccodegenarm64.cpp (854) - Assertion failed 'canRepairTargetOverlap || (targetReg != intrin.op2->GetRegNum()) || genIsSameLocalVar(rmwOp, intrin.op2)' in 'SveBenchmarks.ComplexMultiply:SveComplexMultiply():this' during 'Generate code' (IL size 514; hash 0xcf12aa28; FullOpts)
[17:22:24] [17:22:24] ISSUE: <ASM_DIFF> main method 11328 of size 148 differs
[17:22:24] ISSUE: <ASSERT> #17808 D:\a\_work\1\s\src\coreclr\jit\hwintrinsiccodegenarm64.cpp (854) - Assertion failed 'canRepairTargetOverlap || (targetReg != intrin.op2->GetRegNum()) || genIsSameLocalVar(rmwOp, intrin.op2)' in 'SveBenchmarks.Logarithm:SveLogarithm():this' during 'Generate code' (IL size 666; hash 0xfd45ed08; FullOpts)
[17:22:24] [17:22:24] Compilation failures

These should be fixed now too...

@dhartglassMSFT
dhartglassMSFT enabled auto-merge (squash) June 30, 2026 19:12
@dhartglassMSFT
dhartglassMSFT merged commit 411b771 into dotnet:mainJun 30, 2026
145 of 150 checks passed
@dhartglassMSFT

Copy link
Copy Markdown
Contributor

I merged this, thanks @a74nh and @ylpoon-arm for the fix here!

@dotnet-milestone-botdotnet-milestone-botBot added this to the 11.0-preview7 milestone Jul 1, 2026
@JulieLeeMSFTJulieLeeMSFT added the arm-sve Work related to arm64 SVE/SVE2 support label Jul 1, 2026
eiriktsarpalis pushed a commit that referenced this pull request Jul 15, 2026
This PR is the last part for #115508, with the following changes:
* Cleanup to `hwintrinsiccodegenarm64.cpp`:
* Move the embedded masked block to a new function
`genEmbeddedMaskedHWIntrinsic`.
* Combine codepaths for different number of operand cases and centralize
movprfx logic.
* Optimizations to movprfx usage in embedded masked operation codegen:
* Replace predicated movprfx with unpredicated movprfx when mask is
all-true. Unpredicated movprfx is generally preferred due to
performance.
* Allow zero falseOp to be contained when mask is not all-true so that
zeroing predicated movprfx can be used.
* Allow unary embedded masked ops to use movprfx. Unary embedded masked
ops are not RMW instructions, but may also support movprfx, which
require the target register to be delayed free in LSRA.
* Fixing the Sve HardwareIntrinsics tests `ConditionalSelect_ZeroOp`
calls: The `falseOp->IsVectorZero` branch in the codegen was previously
untested because the zero vector was passed as a local variable rather
than a constant vector. The zero vector needs to be passed directly into
the `ConditionalSelect` intrinsic in the test templates.
---------
Co-authored-by: Alan Hayward <alan.hayward@arm.com>
Co-authored-by: Yat Long Poon <yatlong.poon@arm.com>
Co-authored-by: dhartglassMSFT <dhartglass+github@microsoft.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Aug 1, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMIarm-sveWork related to arm64 SVE/SVE2 supportcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@ylpoonlg@dhartglassMSFT@a74nh@JulieLeeMSFT@ylpoon-arm
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' arm64: Clean up SVE embedded masked codegen by ylpoonlg · Pull Request #127164 · dotnet/runtime · GitHub
Skip to content

arm64: Clean up SVE embedded masked codegen - #127164

Merged
dhartglassMSFT merged 12 commits into
dotnet:mainfrom
ylpoonlg:github-movprfx_refactor_3
Jun 30, 2026
Merged

arm64: Clean up SVE embedded masked codegen#127164
dhartglassMSFT merged 12 commits into
dotnet:mainfrom
ylpoonlg:github-movprfx_refactor_3

Conversation

@ylpoonlg

Copy link
Copy Markdown
Contributor

This PR is the last part for #115508, with the following changes:

  • Cleanup to hwintrinsiccodegenarm64.cpp:

    • Move the embedded masked block to a new function genEmbeddedMaskedHWIntrinsic.
    • Combine codepaths for different number of operand cases and centralize movprfx logic.
  • Optimizations to movprfx usage in embedded masked operation codegen:

    • Replace predicated movprfx with unpredicated movprfx when mask is all-true. Unpredicated movprfx is generally preferred due to performance.
    • Allow zero falseOp to be contained when mask is not all-true so that zeroing predicated movprfx can be used.
    • Allow unary embedded masked ops to use movprfx. Unary embedded masked ops are not RMW instructions, but may also support movprfx, which require the target register to be delayed free in LSRA.
  • Fixing the Sve HardwareIntrinsics tests ConditionalSelect_ZeroOp calls: The falseOp->IsVectorZero branch in the codegen was previously untested because the zero vector was passed as a local variable rather than a constant vector. The zero vector needs to be passed directly into the ConditionalSelect intrinsic in the test templates.

* Move the embedded masked block to a new function.
* Combine codepaths for different number of operand cases.
* Optimise predicated movprfx into unpredicated movprfx when mask is all-true.
* Allow zero falseOp to be contained when mask is not all-true.
* Fix Sve HWIntrin tests ConditionalSelect ZeroOp. The zero vector needs
to be passed directly as constant such that the falseOp->IsVectorZero
branch can be tested.
* Fix LSRA delay free to allow unary embedded masked ops to use movprfx.
@github-actionsgithub-actionsBot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Apr 20, 2026
@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Apr 20, 2026
@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.

@ylpoonlg

Copy link
Copy Markdown
ContributorAuthor

Example SPMI asmdiffs:

@@ -22,11 +22,11 @@
movz x0, #0xD1FFAB1E // data for <unknown class>:<unknown field>
movk x0, #0xD1FFAB1E LSL #16
movk x0, #0xD1FFAB1E LSL #32
ldr q17, [x0]
ptrue p0.d
- movprfx z18.d, p0/z, z16.d+ movprfx z18, z16
fmla z18.d, p0/m, z17.d, z17.d
str q18, [x0]

Replaces predicated movprfx with unpredicated movprfx when predicate is true.

@@ -20,31 +20,30 @@
;; size=16 bbWeight=1 PerfScore 3.50
G_M32226_IG02: ; bbWeight=1, gcrefRegs=0000 {}, byrefRegs=0000 {}, byref
ldr q16, [fp, #0x20] // [V00 arg0]
ldr q17, [fp, #0x10] // [V01 arg1]
ptrue p0.b
- movprfx z16.b, p0/z, z16.b
smax z16.b, p0/m, z16.b, z17.b
mov v0.16b, v16.16b

Removes unnecessary movprfx when moving the same register and predicate is all-true.

@@ -195,14 +191,12 @@
blr x1 // code for <unknown method>
; gcrRegs -[x0]
ldp q1, q3, [x19, #0x30]
mov v2.16b, v3.16b
ptrue p0.d
- movi v0.4s, #0
movprfx z4, z1
faddp z4.d, p0/m, z4.d, z2.d
- sel z4.d, p0, z4.d, z0.d
mvni v0.4s, #0
mov x0, x19
; gcrRegs +[x0]
mov w1, #1
mov x2, x21

Removes unnecessary selects and contain zero vector when mask is all-true.

 ; gcrRegs -[x0]
ldr q0, [x19, #0x18]
ldr q1, [x19, #0x28]
ptrue p0.d
cmpne p0.d, p0/z, z0.d, #0
- movi v3.4s, #0+ movprfx z3.d, p0/z, z3.d
frintn z3.d, p0/m, z1.d
movi v2.4s, #0
mov x0, x19
; gcrRegs +[x0]
mov w1, #1

Contains the zero vector and use zeroing movprfx.

@@ -150,13 +150,14 @@
ptrue p0.s
cmpne p0.s, p0/z, z8.s, #0
movi v16.4s, #0
mov z12.d, z9.d
fcvtnt z12.s, p0/m, z10.d
+ sel z12.s, p0, z12.s, z16.s
str q12, [fp, #0x20] // [V07 tmp6]
b G_M36822_IG05

Fixes a bug with inactive lanes for ConvertToSingleOdd. This was revealed by the changes to the test templates.

@ylpoonlg
ylpoonlg marked this pull request as ready for review April 23, 2026 16:28
@ylpoonlg

Copy link
Copy Markdown
ContributorAuthor

jitstressregs passes locally.

@dotnet/arm64-contrib @a74nh@dhartglassMSFT

@ylpoonlg

Copy link
Copy Markdown
ContributorAuthor

error : (NETCORE_ENGINEERING_TELEMETRY=Test) Test JIT/opt/SVE/ConstantMasks/ConstantMasks.cmd has failed.

Some optimization tests are failing, I will look into them further.

Comment threadsrc/coreclr/jit/lsraarm64.cpp
Comment threadsrc/coreclr/jit/lsraarm64.cpp
Comment threadsrc/coreclr/jit/hwintrinsiccodegenarm64.cpp Outdated
Comment threadsrc/coreclr/jit/hwintrinsiccodegenarm64.cpp Outdated
@ylpoonlg

Copy link
Copy Markdown
ContributorAuthor

There is still a failing SVE opt test ConstantMasks:

 552: G_M15649_IG02:
553: ptrue p0.s
554: abs z16.s, p0/m, z0.s
555: mov v0.16b, v16.16b
556: movz x0, #0xD1FFAB1E // code for ConstantMasks:Consume[System.Numerics.Vector`1[int]](System.Numerics.Vector`1[int])
next:179 !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: match on wrong line

The LSRA change caused an extra mov v0.16b, v16.16b, but I have not been able to prioritize the destination register over op1 (any ideas would be appreciated). This was done to allow for movprfx usage, but in this case the ptrue suppressed it, so it doesn't really need to be delayed free. Maybe I should revert to using SVE mov instead of movprfx for now, and leave this for #107134.

@dhartglassMSFT

Copy link
Copy Markdown
Contributor

There is still a failing SVE opt test ConstantMasks:

 552: G_M15649_IG02:
553: ptrue p0.s
554: abs z16.s, p0/m, z0.s
555: mov v0.16b, v16.16b
556: movz x0, #0xD1FFAB1E // code for ConstantMasks:Consume[System.Numerics.Vector`1[int]](System.Numerics.Vector`1[int])
next:179 !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: match on wrong line

The LSRA change caused an extra mov v0.16b, v16.16b, but I have not been able to prioritize the destination register over op1 (any ideas would be appreciated). This was done to allow for movprfx usage, but in this case the ptrue suppressed it, so it doesn't really need to be delayed free. Maybe I should revert to using SVE mov instead of movprfx for now, and leave this for #107134.

Hey @ylpoonlg@a74nh following up on this. I may have lost some context, but during lsra we know whether the mask is all true, correct? In any case let me know if you needed further follow-up here, sorry for the delay

@ylpoonlg

Copy link
Copy Markdown
ContributorAuthor

There is still a failing SVE opt test ConstantMasks:

 552: G_M15649_IG02:
553: ptrue p0.s
554: abs z16.s, p0/m, z0.s
555: mov v0.16b, v16.16b
556: movz x0, #0xD1FFAB1E // code for ConstantMasks:Consume[System.Numerics.Vector`1[int]](System.Numerics.Vector`1[int])
next:179 !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: match on wrong line

The LSRA change caused an extra mov v0.16b, v16.16b, but I have not been able to prioritize the destination register over op1 (any ideas would be appreciated). This was done to allow for movprfx usage, but in this case the ptrue suppressed it, so it doesn't really need to be delayed free. Maybe I should revert to using SVE mov instead of movprfx for now, and leave this for #107134.

Hey @ylpoonlg@a74nh following up on this. I may have lost some context, but during lsra we know whether the mask is all true, correct? In any case let me know if you needed further follow-up here, sorry for the delay

Thanks for looking at this. I think currently lsra is delay-freeing operands for all RMW instructions(#107134), but this is fine for now. The main issue here is the unary embedded masked operations, since they are not RMW but also support MOVPRFX. I attempted to enable its usage by allowing delay free in lsra, but looks like it is not assigning the registers optimally, causing the test failure:
For example with

abs z16.s, p0/m, z0.s
mov v0.16b, v16.16b

the extra mov is unnecessary if it can use the destination register directly and use a different source register:

abs z0.s, p0/m, z16.s

If this lsra is too complicated to fix in this PR, I can remove this particular optimization and not use MOVPRFX with unary embedded masked operations for now.

@a74nh

Copy link
Copy Markdown
Contributor

@ylpoonlg : I've taken a look at this and made some fixes in LSRA, which fix up the regressions in both Abs and ConvertToSingleOdd. I don't have the permissions to push directly to this PR, so could you please take a look at my two commits and add them into this PR (assuming you're happy with the changes 😄 ).

https://github.com/dotnet/runtime/compare/main...a74nh:runtime:github-movprfx_refactor_3?expand=1

@a74nha74nh mentioned this pull request Jun 24, 2026
20 tasks
@dhartglassMSFT

Copy link
Copy Markdown
Contributor

/azp run runtime-coreclr jitstressregs

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@dhartglassMSFT

Copy link
Copy Markdown
Contributor

/azp run runtime-coreclr jitstressregs

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@dhartglassMSFT

Copy link
Copy Markdown
Contributor

last regstress hit a known issue, kicking off a new one

@a74nh

Copy link
Copy Markdown
Contributor

@dhartglassMSFT - did something go wrong with the stress run again?

@dhartglassMSFT

Copy link
Copy Markdown
Contributor

/azp run runtime-coreclr jitstressregs

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@dhartglassMSFT

Copy link
Copy Markdown
Contributor

@dhartglassMSFT - did something go wrong with the stress run again?

It will surely work on the third try

@dhartglassMSFT

Copy link
Copy Markdown
Contributor

@a74nh I took another look, unfortunately the SPMI failures appear related.

[01:51:17] ISSUE: <ASSERT> #61471 D:\a\_work\1\s\src\coreclr\jit\hwintrinsiccodegenarm64.cpp (824) - Assertion failed '(targetReg != intrin.op2->GetRegNum()) || genIsSameLocalVar(rmwOp, intrin.op2)' in 'SveBenchmarks.ComplexMultiply:SveComplexMultiply():this' during 'Generate code' (IL size 514; hash 0xcf12aa28; FullOpts)

@dhartglassMSFT

dhartglassMSFT commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

@a74nh I had missed there were also these two in the SPMI output.

This now should be al the failures, apologies for missing these on my first glance yesterday
(same assert twice)

[17:22:24] ISSUE: <ASM_DIFF> main method 15075 of size 301 differs
[17:22:24] ISSUE: <ASM_DIFF> main method 18555 of size 535 differs
[17:22:24] ISSUE: <ASSERT> #21871 D:\a\_work\1\s\src\coreclr\jit\hwintrinsiccodegenarm64.cpp (854) - Assertion failed 'canRepairTargetOverlap || (targetReg != intrin.op2->GetRegNum()) || genIsSameLocalVar(rmwOp, intrin.op2)' in 'SveBenchmarks.ComplexMultiply:SveComplexMultiply():this' during 'Generate code' (IL size 514; hash 0xcf12aa28; FullOpts)
[17:22:24] [17:22:24] ISSUE: <ASM_DIFF> main method 11328 of size 148 differs
[17:22:24] ISSUE: <ASSERT> #17808 D:\a\_work\1\s\src\coreclr\jit\hwintrinsiccodegenarm64.cpp (854) - Assertion failed 'canRepairTargetOverlap || (targetReg != intrin.op2->GetRegNum()) || genIsSameLocalVar(rmwOp, intrin.op2)' in 'SveBenchmarks.Logarithm:SveLogarithm():this' during 'Generate code' (IL size 666; hash 0xfd45ed08; FullOpts)
[17:22:24] [17:22:24] Compilation failures

@a74nh

Copy link
Copy Markdown
Contributor

@a74nh I had missed there were also these two in the SPMI output.

This now should be al the failures, apologies for missing these on my first glance yesterday (same assert twice)

[17:22:24] ISSUE: <ASM_DIFF> main method 15075 of size 301 differs
[17:22:24] ISSUE: <ASM_DIFF> main method 18555 of size 535 differs
[17:22:24] ISSUE: <ASSERT> #21871 D:\a\_work\1\s\src\coreclr\jit\hwintrinsiccodegenarm64.cpp (854) - Assertion failed 'canRepairTargetOverlap || (targetReg != intrin.op2->GetRegNum()) || genIsSameLocalVar(rmwOp, intrin.op2)' in 'SveBenchmarks.ComplexMultiply:SveComplexMultiply():this' during 'Generate code' (IL size 514; hash 0xcf12aa28; FullOpts)
[17:22:24] [17:22:24] ISSUE: <ASM_DIFF> main method 11328 of size 148 differs
[17:22:24] ISSUE: <ASSERT> #17808 D:\a\_work\1\s\src\coreclr\jit\hwintrinsiccodegenarm64.cpp (854) - Assertion failed 'canRepairTargetOverlap || (targetReg != intrin.op2->GetRegNum()) || genIsSameLocalVar(rmwOp, intrin.op2)' in 'SveBenchmarks.Logarithm:SveLogarithm():this' during 'Generate code' (IL size 666; hash 0xfd45ed08; FullOpts)
[17:22:24] [17:22:24] Compilation failures

These should be fixed now too...

@dhartglassMSFT
dhartglassMSFT enabled auto-merge (squash) June 30, 2026 19:12
@dhartglassMSFT
dhartglassMSFT merged commit 411b771 into dotnet:mainJun 30, 2026
145 of 150 checks passed
@dhartglassMSFT

Copy link
Copy Markdown
Contributor

I merged this, thanks @a74nh and @ylpoon-arm for the fix here!

@dotnet-milestone-botdotnet-milestone-botBot added this to the 11.0-preview7 milestone Jul 1, 2026
@JulieLeeMSFTJulieLeeMSFT added the arm-sve Work related to arm64 SVE/SVE2 support label Jul 1, 2026
eiriktsarpalis pushed a commit that referenced this pull request Jul 15, 2026
This PR is the last part for #115508, with the following changes:
* Cleanup to `hwintrinsiccodegenarm64.cpp`:
* Move the embedded masked block to a new function
`genEmbeddedMaskedHWIntrinsic`.
* Combine codepaths for different number of operand cases and centralize
movprfx logic.
* Optimizations to movprfx usage in embedded masked operation codegen:
* Replace predicated movprfx with unpredicated movprfx when mask is
all-true. Unpredicated movprfx is generally preferred due to
performance.
* Allow zero falseOp to be contained when mask is not all-true so that
zeroing predicated movprfx can be used.
* Allow unary embedded masked ops to use movprfx. Unary embedded masked
ops are not RMW instructions, but may also support movprfx, which
require the target register to be delayed free in LSRA.
* Fixing the Sve HardwareIntrinsics tests `ConditionalSelect_ZeroOp`
calls: The `falseOp->IsVectorZero` branch in the codegen was previously
untested because the zero vector was passed as a local variable rather
than a constant vector. The zero vector needs to be passed directly into
the `ConditionalSelect` intrinsic in the test templates.
---------
Co-authored-by: Alan Hayward <alan.hayward@arm.com>
Co-authored-by: Yat Long Poon <yatlong.poon@arm.com>
Co-authored-by: dhartglassMSFT <dhartglass+github@microsoft.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Aug 1, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMIarm-sveWork related to arm64 SVE/SVE2 supportcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@ylpoonlg@dhartglassMSFT@a74nh@JulieLeeMSFT@ylpoon-arm
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); arm64: Clean up SVE embedded masked codegen by ylpoonlg · Pull Request #127164 · dotnet/runtime · GitHub
Skip to content

arm64: Clean up SVE embedded masked codegen - #127164

Merged
dhartglassMSFT merged 12 commits into
dotnet:mainfrom
ylpoonlg:github-movprfx_refactor_3
Jun 30, 2026
Merged

arm64: Clean up SVE embedded masked codegen#127164
dhartglassMSFT merged 12 commits into
dotnet:mainfrom
ylpoonlg:github-movprfx_refactor_3

Conversation

@ylpoonlg

Copy link
Copy Markdown
Contributor

This PR is the last part for #115508, with the following changes:

  • Cleanup to hwintrinsiccodegenarm64.cpp:

    • Move the embedded masked block to a new function genEmbeddedMaskedHWIntrinsic.
    • Combine codepaths for different number of operand cases and centralize movprfx logic.
  • Optimizations to movprfx usage in embedded masked operation codegen:

    • Replace predicated movprfx with unpredicated movprfx when mask is all-true. Unpredicated movprfx is generally preferred due to performance.
    • Allow zero falseOp to be contained when mask is not all-true so that zeroing predicated movprfx can be used.
    • Allow unary embedded masked ops to use movprfx. Unary embedded masked ops are not RMW instructions, but may also support movprfx, which require the target register to be delayed free in LSRA.
  • Fixing the Sve HardwareIntrinsics tests ConditionalSelect_ZeroOp calls: The falseOp->IsVectorZero branch in the codegen was previously untested because the zero vector was passed as a local variable rather than a constant vector. The zero vector needs to be passed directly into the ConditionalSelect intrinsic in the test templates.

* Move the embedded masked block to a new function.
* Combine codepaths for different number of operand cases.
* Optimise predicated movprfx into unpredicated movprfx when mask is all-true.
* Allow zero falseOp to be contained when mask is not all-true.
* Fix Sve HWIntrin tests ConditionalSelect ZeroOp. The zero vector needs
to be passed directly as constant such that the falseOp->IsVectorZero
branch can be tested.
* Fix LSRA delay free to allow unary embedded masked ops to use movprfx.
@github-actionsgithub-actionsBot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Apr 20, 2026
@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Apr 20, 2026
@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.

@ylpoonlg

Copy link
Copy Markdown
ContributorAuthor

Example SPMI asmdiffs:

@@ -22,11 +22,11 @@
movz x0, #0xD1FFAB1E // data for <unknown class>:<unknown field>
movk x0, #0xD1FFAB1E LSL #16
movk x0, #0xD1FFAB1E LSL #32
ldr q17, [x0]
ptrue p0.d
- movprfx z18.d, p0/z, z16.d+ movprfx z18, z16
fmla z18.d, p0/m, z17.d, z17.d
str q18, [x0]

Replaces predicated movprfx with unpredicated movprfx when predicate is true.

@@ -20,31 +20,30 @@
;; size=16 bbWeight=1 PerfScore 3.50
G_M32226_IG02: ; bbWeight=1, gcrefRegs=0000 {}, byrefRegs=0000 {}, byref
ldr q16, [fp, #0x20] // [V00 arg0]
ldr q17, [fp, #0x10] // [V01 arg1]
ptrue p0.b
- movprfx z16.b, p0/z, z16.b
smax z16.b, p0/m, z16.b, z17.b
mov v0.16b, v16.16b

Removes unnecessary movprfx when moving the same register and predicate is all-true.

@@ -195,14 +191,12 @@
blr x1 // code for <unknown method>
; gcrRegs -[x0]
ldp q1, q3, [x19, #0x30]
mov v2.16b, v3.16b
ptrue p0.d
- movi v0.4s, #0
movprfx z4, z1
faddp z4.d, p0/m, z4.d, z2.d
- sel z4.d, p0, z4.d, z0.d
mvni v0.4s, #0
mov x0, x19
; gcrRegs +[x0]
mov w1, #1
mov x2, x21

Removes unnecessary selects and contain zero vector when mask is all-true.

 ; gcrRegs -[x0]
ldr q0, [x19, #0x18]
ldr q1, [x19, #0x28]
ptrue p0.d
cmpne p0.d, p0/z, z0.d, #0
- movi v3.4s, #0+ movprfx z3.d, p0/z, z3.d
frintn z3.d, p0/m, z1.d
movi v2.4s, #0
mov x0, x19
; gcrRegs +[x0]
mov w1, #1

Contains the zero vector and use zeroing movprfx.

@@ -150,13 +150,14 @@
ptrue p0.s
cmpne p0.s, p0/z, z8.s, #0
movi v16.4s, #0
mov z12.d, z9.d
fcvtnt z12.s, p0/m, z10.d
+ sel z12.s, p0, z12.s, z16.s
str q12, [fp, #0x20] // [V07 tmp6]
b G_M36822_IG05

Fixes a bug with inactive lanes for ConvertToSingleOdd. This was revealed by the changes to the test templates.

@ylpoonlg
ylpoonlg marked this pull request as ready for review April 23, 2026 16:28
@ylpoonlg

Copy link
Copy Markdown
ContributorAuthor

jitstressregs passes locally.

@dotnet/arm64-contrib @a74nh@dhartglassMSFT

@ylpoonlg

Copy link
Copy Markdown
ContributorAuthor

error : (NETCORE_ENGINEERING_TELEMETRY=Test) Test JIT/opt/SVE/ConstantMasks/ConstantMasks.cmd has failed.

Some optimization tests are failing, I will look into them further.

Comment threadsrc/coreclr/jit/lsraarm64.cpp
Comment threadsrc/coreclr/jit/lsraarm64.cpp
Comment threadsrc/coreclr/jit/hwintrinsiccodegenarm64.cpp Outdated
Comment threadsrc/coreclr/jit/hwintrinsiccodegenarm64.cpp Outdated
@ylpoonlg

Copy link
Copy Markdown
ContributorAuthor

There is still a failing SVE opt test ConstantMasks:

 552: G_M15649_IG02:
553: ptrue p0.s
554: abs z16.s, p0/m, z0.s
555: mov v0.16b, v16.16b
556: movz x0, #0xD1FFAB1E // code for ConstantMasks:Consume[System.Numerics.Vector`1[int]](System.Numerics.Vector`1[int])
next:179 !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: match on wrong line

The LSRA change caused an extra mov v0.16b, v16.16b, but I have not been able to prioritize the destination register over op1 (any ideas would be appreciated). This was done to allow for movprfx usage, but in this case the ptrue suppressed it, so it doesn't really need to be delayed free. Maybe I should revert to using SVE mov instead of movprfx for now, and leave this for #107134.

@dhartglassMSFT

Copy link
Copy Markdown
Contributor

There is still a failing SVE opt test ConstantMasks:

 552: G_M15649_IG02:
553: ptrue p0.s
554: abs z16.s, p0/m, z0.s
555: mov v0.16b, v16.16b
556: movz x0, #0xD1FFAB1E // code for ConstantMasks:Consume[System.Numerics.Vector`1[int]](System.Numerics.Vector`1[int])
next:179 !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: match on wrong line

The LSRA change caused an extra mov v0.16b, v16.16b, but I have not been able to prioritize the destination register over op1 (any ideas would be appreciated). This was done to allow for movprfx usage, but in this case the ptrue suppressed it, so it doesn't really need to be delayed free. Maybe I should revert to using SVE mov instead of movprfx for now, and leave this for #107134.

Hey @ylpoonlg@a74nh following up on this. I may have lost some context, but during lsra we know whether the mask is all true, correct? In any case let me know if you needed further follow-up here, sorry for the delay

@ylpoonlg

Copy link
Copy Markdown
ContributorAuthor

There is still a failing SVE opt test ConstantMasks:

 552: G_M15649_IG02:
553: ptrue p0.s
554: abs z16.s, p0/m, z0.s
555: mov v0.16b, v16.16b
556: movz x0, #0xD1FFAB1E // code for ConstantMasks:Consume[System.Numerics.Vector`1[int]](System.Numerics.Vector`1[int])
next:179 !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: match on wrong line

The LSRA change caused an extra mov v0.16b, v16.16b, but I have not been able to prioritize the destination register over op1 (any ideas would be appreciated). This was done to allow for movprfx usage, but in this case the ptrue suppressed it, so it doesn't really need to be delayed free. Maybe I should revert to using SVE mov instead of movprfx for now, and leave this for #107134.

Hey @ylpoonlg@a74nh following up on this. I may have lost some context, but during lsra we know whether the mask is all true, correct? In any case let me know if you needed further follow-up here, sorry for the delay

Thanks for looking at this. I think currently lsra is delay-freeing operands for all RMW instructions(#107134), but this is fine for now. The main issue here is the unary embedded masked operations, since they are not RMW but also support MOVPRFX. I attempted to enable its usage by allowing delay free in lsra, but looks like it is not assigning the registers optimally, causing the test failure:
For example with

abs z16.s, p0/m, z0.s
mov v0.16b, v16.16b

the extra mov is unnecessary if it can use the destination register directly and use a different source register:

abs z0.s, p0/m, z16.s

If this lsra is too complicated to fix in this PR, I can remove this particular optimization and not use MOVPRFX with unary embedded masked operations for now.

@a74nh

Copy link
Copy Markdown
Contributor

@ylpoonlg : I've taken a look at this and made some fixes in LSRA, which fix up the regressions in both Abs and ConvertToSingleOdd. I don't have the permissions to push directly to this PR, so could you please take a look at my two commits and add them into this PR (assuming you're happy with the changes 😄 ).

https://github.com/dotnet/runtime/compare/main...a74nh:runtime:github-movprfx_refactor_3?expand=1

@a74nha74nh mentioned this pull request Jun 24, 2026
20 tasks
@dhartglassMSFT

Copy link
Copy Markdown
Contributor

/azp run runtime-coreclr jitstressregs

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@dhartglassMSFT

Copy link
Copy Markdown
Contributor

/azp run runtime-coreclr jitstressregs

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@dhartglassMSFT

Copy link
Copy Markdown
Contributor

last regstress hit a known issue, kicking off a new one

@a74nh

Copy link
Copy Markdown
Contributor

@dhartglassMSFT - did something go wrong with the stress run again?

@dhartglassMSFT

Copy link
Copy Markdown
Contributor

/azp run runtime-coreclr jitstressregs

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@dhartglassMSFT

Copy link
Copy Markdown
Contributor

@dhartglassMSFT - did something go wrong with the stress run again?

It will surely work on the third try

@dhartglassMSFT

Copy link
Copy Markdown
Contributor

@a74nh I took another look, unfortunately the SPMI failures appear related.

[01:51:17] ISSUE: <ASSERT> #61471 D:\a\_work\1\s\src\coreclr\jit\hwintrinsiccodegenarm64.cpp (824) - Assertion failed '(targetReg != intrin.op2->GetRegNum()) || genIsSameLocalVar(rmwOp, intrin.op2)' in 'SveBenchmarks.ComplexMultiply:SveComplexMultiply():this' during 'Generate code' (IL size 514; hash 0xcf12aa28; FullOpts)

@dhartglassMSFT

dhartglassMSFT commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

@a74nh I had missed there were also these two in the SPMI output.

This now should be al the failures, apologies for missing these on my first glance yesterday
(same assert twice)

[17:22:24] ISSUE: <ASM_DIFF> main method 15075 of size 301 differs
[17:22:24] ISSUE: <ASM_DIFF> main method 18555 of size 535 differs
[17:22:24] ISSUE: <ASSERT> #21871 D:\a\_work\1\s\src\coreclr\jit\hwintrinsiccodegenarm64.cpp (854) - Assertion failed 'canRepairTargetOverlap || (targetReg != intrin.op2->GetRegNum()) || genIsSameLocalVar(rmwOp, intrin.op2)' in 'SveBenchmarks.ComplexMultiply:SveComplexMultiply():this' during 'Generate code' (IL size 514; hash 0xcf12aa28; FullOpts)
[17:22:24] [17:22:24] ISSUE: <ASM_DIFF> main method 11328 of size 148 differs
[17:22:24] ISSUE: <ASSERT> #17808 D:\a\_work\1\s\src\coreclr\jit\hwintrinsiccodegenarm64.cpp (854) - Assertion failed 'canRepairTargetOverlap || (targetReg != intrin.op2->GetRegNum()) || genIsSameLocalVar(rmwOp, intrin.op2)' in 'SveBenchmarks.Logarithm:SveLogarithm():this' during 'Generate code' (IL size 666; hash 0xfd45ed08; FullOpts)
[17:22:24] [17:22:24] Compilation failures

@a74nh

Copy link
Copy Markdown
Contributor

@a74nh I had missed there were also these two in the SPMI output.

This now should be al the failures, apologies for missing these on my first glance yesterday (same assert twice)

[17:22:24] ISSUE: <ASM_DIFF> main method 15075 of size 301 differs
[17:22:24] ISSUE: <ASM_DIFF> main method 18555 of size 535 differs
[17:22:24] ISSUE: <ASSERT> #21871 D:\a\_work\1\s\src\coreclr\jit\hwintrinsiccodegenarm64.cpp (854) - Assertion failed 'canRepairTargetOverlap || (targetReg != intrin.op2->GetRegNum()) || genIsSameLocalVar(rmwOp, intrin.op2)' in 'SveBenchmarks.ComplexMultiply:SveComplexMultiply():this' during 'Generate code' (IL size 514; hash 0xcf12aa28; FullOpts)
[17:22:24] [17:22:24] ISSUE: <ASM_DIFF> main method 11328 of size 148 differs
[17:22:24] ISSUE: <ASSERT> #17808 D:\a\_work\1\s\src\coreclr\jit\hwintrinsiccodegenarm64.cpp (854) - Assertion failed 'canRepairTargetOverlap || (targetReg != intrin.op2->GetRegNum()) || genIsSameLocalVar(rmwOp, intrin.op2)' in 'SveBenchmarks.Logarithm:SveLogarithm():this' during 'Generate code' (IL size 666; hash 0xfd45ed08; FullOpts)
[17:22:24] [17:22:24] Compilation failures

These should be fixed now too...

@dhartglassMSFT
dhartglassMSFT enabled auto-merge (squash) June 30, 2026 19:12
@dhartglassMSFT
dhartglassMSFT merged commit 411b771 into dotnet:mainJun 30, 2026
145 of 150 checks passed
@dhartglassMSFT

Copy link
Copy Markdown
Contributor

I merged this, thanks @a74nh and @ylpoon-arm for the fix here!

@dotnet-milestone-botdotnet-milestone-botBot added this to the 11.0-preview7 milestone Jul 1, 2026
@JulieLeeMSFTJulieLeeMSFT added the arm-sve Work related to arm64 SVE/SVE2 support label Jul 1, 2026
eiriktsarpalis pushed a commit that referenced this pull request Jul 15, 2026
This PR is the last part for #115508, with the following changes:
* Cleanup to `hwintrinsiccodegenarm64.cpp`:
* Move the embedded masked block to a new function
`genEmbeddedMaskedHWIntrinsic`.
* Combine codepaths for different number of operand cases and centralize
movprfx logic.
* Optimizations to movprfx usage in embedded masked operation codegen:
* Replace predicated movprfx with unpredicated movprfx when mask is
all-true. Unpredicated movprfx is generally preferred due to
performance.
* Allow zero falseOp to be contained when mask is not all-true so that
zeroing predicated movprfx can be used.
* Allow unary embedded masked ops to use movprfx. Unary embedded masked
ops are not RMW instructions, but may also support movprfx, which
require the target register to be delayed free in LSRA.
* Fixing the Sve HardwareIntrinsics tests `ConditionalSelect_ZeroOp`
calls: The `falseOp->IsVectorZero` branch in the codegen was previously
untested because the zero vector was passed as a local variable rather
than a constant vector. The zero vector needs to be passed directly into
the `ConditionalSelect` intrinsic in the test templates.
---------
Co-authored-by: Alan Hayward <alan.hayward@arm.com>
Co-authored-by: Yat Long Poon <yatlong.poon@arm.com>
Co-authored-by: dhartglassMSFT <dhartglass+github@microsoft.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Aug 1, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMIarm-sveWork related to arm64 SVE/SVE2 supportcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@ylpoonlg@dhartglassMSFT@a74nh@JulieLeeMSFT@ylpoon-arm