arm64: Clean up SVE embedded masked codegen#127164
Conversation
* 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.
|
Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch |
|
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.16bRemoves 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, x21Removes 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, #1Contains 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_IG05Fixes a bug with inactive lanes for |
|
jitstressregs passes locally. @dotnet/arm64-contrib @a74nh @dhartglassMSFT |
Some optimization tests are failing, I will look into them further. |
|
There is still a failing SVE opt test The LSRA change caused an extra |
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: the extra 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. |
|
@ylpoonlg : I've taken a look at this and made some fixes in LSRA, which fix up the regressions in both https://github.com/dotnet/runtime/compare/main...a74nh:runtime:github-movprfx_refactor_3?expand=1 |
|
/azp run runtime-coreclr jitstressregs |
|
Azure Pipelines successfully started running 1 pipeline(s). |
|
/azp run runtime-coreclr jitstressregs |
|
Azure Pipelines successfully started running 1 pipeline(s). |
|
last regstress hit a known issue, kicking off a new one |
|
@dhartglassMSFT - did something go wrong with the stress run again? |
|
/azp run runtime-coreclr jitstressregs |
|
Azure Pipelines successfully started running 1 pipeline(s). |
It will surely work on the third try |
|
@a74nh I took another look, unfortunately the SPMI failures appear related. |
|
@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 |
These should be fixed now too... |
|
I merged this, thanks @a74nh and @ylpoon-arm for the fix here! |
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>
This PR is the last part for #115508, with the following changes:
Cleanup to
hwintrinsiccodegenarm64.cpp:genEmbeddedMaskedHWIntrinsic.Optimizations to movprfx usage in embedded masked operation codegen:
Fixing the Sve HardwareIntrinsics tests
ConditionalSelect_ZeroOpcalls: ThefalseOp->IsVectorZerobranch 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 theConditionalSelectintrinsic in the test templates.