Implement StoreSelectedScalar for Arm64 - #93223

Merged
kunalspathak merged 24 commits into
dotnet:mainfrom
SwapnilGaikwad:github-st2-indexed
Nov 16, 2023
Merged

Implement StoreSelectedScalar for Arm64#93223
kunalspathak merged 24 commits into
dotnet:mainfrom
SwapnilGaikwad:github-st2-indexed

Conversation

@SwapnilGaikwad

@SwapnilGaikwadSwapnilGaikwad commented Oct 9, 2023

Copy link
Copy Markdown
Contributor

Contribute towards #84510.

// AdvSimd// ST2 (single structure)publicstaticunsafevoidStoreSelectedScalar64x2(byte*address,(Vector64<byte>Value1,Vector64<byte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(sbyte*address,(Vector64<sbyte>Value1,Vector64<sbyte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(short*address,(Vector64<short>Value1,Vector64<short>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(ushort*address,(Vector64<ushort>Value1,Vector64<ushort>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(int*address,(Vector64<int>Value1,Vector64<int>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(uint*address,(Vector64<uint>Value1,Vector64<uint>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(float*address,(Vector64<float>Value1,Vector64<float>Value2)value,byteindex);// ST3 (single structure)publicstaticunsafevoidStoreSelectedScalar64x3(byte*address,(Vector64<byte>Value1,Vector64<byte>Value2,Vector64<byte>Value3)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x3(sbyte*address,(Vector64<sbyte>Value1,Vector64<sbyte>Value2,Vector64<sbyte>Value3)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x3(short*address,(Vector64<short>Value1,Vector64<short>Value2,Vector64<short>Value3)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x3(ushort*address,(Vector64<ushort>Value1,Vector64<ushort>Value2,Vector64<ushort>Value3)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x3(int*address,(Vector64<int>Value1,Vector64<int>Value2,Vector64<int>Value3)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x3(uint*address,(Vector64<uint>Value1,Vector64<uint>Value2,Vector64<uint>Value3)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x3(float*address,(Vector64<float>Value1,Vector64<float>Value2,Vector64<float>Value3)value,byteindex);// ST4 (single structure)publicstaticunsafevoidStoreSelectedScalar64x4(byte*address,(Vector64<byte>Value1,Vector64<byte>Value2,Vector64<byte>Value3,Vector64<byte>Value4)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x4(sbyte*address,(Vector64<sbyte>Value1,Vector64<sbyte>Value2,Vector64<sbyte>Value3,Vector64<sbyte>Value4)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x4(short*address,(Vector64<short>Value1,Vector64<short>Value2,Vector64<short>Value3,Vector64<short>Value4)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x4(ushort*address,(Vector64<ushort>Value1,Vector64<ushort>Value2,Vector64<ushort>Value3,Vector64<ushort>Value4)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x4(int*address,(Vector64<int>Value1,Vector64<int>Value2,Vector64<int>Value3,Vector64<int>Value4)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x4(uint*address,(Vector64<uint>Value1,Vector64<uint>Value2,Vector64<uint>Value3,Vector64<uint>Value4)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x4(float*address,(Vector64<float>Value1,Vector64<float>Value2,Vector64<float>Value3,Vector64<float>Value4)value,byteindex);// AdvSimd.Arm64// ST2 (single structure)publicstaticunsafevoidStoreSelectedScalar128x2(byte*address,(Vector128<byte>Value1,Vector128<byte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(sbyte*address,(Vector128<sbyte>Value1,Vector128<sbyte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(short*address,(Vector128<short>Value1,Vector128<short>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(ushort*address,(Vector128<ushort>Value1,Vector128<ushort>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(int*address,(Vector128<int>Value1,Vector128<int>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(uint*address,(Vector128<uint>Value1,Vector128<uint>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(long*address,(Vector128<long>Value1,Vector128<long>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(ulong*address,(Vector128<ulong>Value1,Vector128<ulong>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(float*address,(Vector128<float>Value1,Vector128<float>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(double*address,(Vector128<double>Value1,Vector128<double>Value2)value,byteindex);// ST3 (single structure)publicstaticunsafevoidStoreSelectedScalar128x3(byte*address,(Vector128<byte>Value1,Vector128<byte>Value2,Vector128<byte>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(sbyte*address,(Vector128<sbyte>Value1,Vector128<sbyte>Value2,Vector128<sbyte>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(short*address,(Vector128<short>Value1,Vector128<short>Value2,Vector128<short>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(ushort*address,(Vector128<ushort>Value1,Vector128<ushort>Value2,Vector128<ushort>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(int*address,(Vector128<int>Value1,Vector128<int>Value2,Vector128<int>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(uint*address,(Vector128<uint>Value1,Vector128<uint>Value2,Vector128<uint>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(long*address,(Vector128<long>Value1,Vector128<long>Value2,Vector128<long>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(ulong*address,(Vector128<ulong>Value1,Vector128<ulong>Value2,Vector128<ulong>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(float*address,(Vector128<float>Value1,Vector128<float>Value2,Vector128<float>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(double*address,(Vector128<double>Value1,Vector128<double>Value2,Vector128<double>Value3),byteindex);// ST4 (single structure)publicstaticunsafevoidStoreSelectedScalar128x4(byte*address,(Vector128<byte>Value1,Vector128<byte>Value2,Vector128<byte>Value3,Vector128<byte>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(sbyte*address,(Vector128<sbyte>Value1,Vector128<sbyte>Value2,Vector128<sbyte>Value3,Vector128<sbyte>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(short*address,(Vector128<short>Value1,Vector128<short>Value2,Vector128<short>Value3,Vector128<short>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(ushort*address,(Vector128<ushort>Value1,Vector128<ushort>Value2,Vector128<ushort>Value3,Vector128<ushort>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(int*address,(Vector128<int>Value1,Vector128<int>Value2,Vector128<int>Value3,Vector128<int>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(uint*address,(Vector128<uint>Value1,Vector128<uint>Value2,Vector128<uint>Value3,Vector128<uint>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(long*address,(Vector128<long>Value1,Vector128<long>Value2,Vector128<long>Value3,Vector128<long>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(ulong*address,(Vector128<ulong>Value1,Vector128<ulong>Value2,Vector128<ulong>Value3,Vector128<ulong>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(float*address,(Vector128<float>Value1,Vector128<float>Value2,Vector128<float>Value3,Vector128<float>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(double*address,(Vector128<double>Value1,Vector128<double>Value2,Vector128<double>Value3,Vector128<double>Value4),byteindex);

@ghostghost added community-contribution Indicates that the PR has been added by a community member area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI new-api-needs-documentation labels Oct 9, 2023
@ghost

ghost commented Oct 9, 2023

Copy link
Copy Markdown

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

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

@ghost

ghost commented Oct 9, 2023

Copy link
Copy Markdown

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

Issue Details

Contribute towards #84510.

// AdvSimdpublicstaticunsafevoidStoreSelectedScalar64x2(byte*address,(Vector64<byte>Value1,Vector64<byte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(sbyte*address,(Vector64<sbyte>Value1,Vector64<sbyte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(short*address,(Vector64<short>Value1,Vector64<short>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(ushort*address,(Vector64<ushort>Value1,Vector64<ushort>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(int*address,(Vector64<int>Value1,Vector64<int>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(uint*address,(Vector64<uint>Value1,Vector64<uint>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(float*address,(Vector64<float>Value1,Vector64<float>Value2)value,byteindex);// AdvSimd.Arm64publicstaticunsafevoidStoreSelectedScalar128x2(byte*address,(Vector128<byte>Value1,Vector128<byte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(sbyte*address,(Vector128<sbyte>Value1,Vector128<sbyte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(short*address,(Vector128<short>Value1,Vector128<short>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(ushort*address,(Vector128<ushort>Value1,Vector128<ushort>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(int*address,(Vector128<int>Value1,Vector128<int>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(uint*address,(Vector128<uint>Value1,Vector128<uint>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(long*address,(Vector128<long>Value1,Vector128<long>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(ulong*address,(Vector128<ulong>Value1,Vector128<ulong>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(float*address,(Vector128<float>Value1,Vector128<float>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(double*address,(Vector128<double>Value1,Vector128<double>Value2)value,byteindex);
Author:SwapnilGaikwad
Assignees:-
Labels:

area-CodeGen-coreclr, new-api-needs-documentation, community-contribution

Milestone:-

@SwapnilGaikwad

Copy link
Copy Markdown
ContributorAuthor

This patch would emit the following assembly sequence

1. When the index is a constant value
AdvSimd.StoreSelectedScalar64x2((Int32*)_dataTable.outArrayPtr,(AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)),AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr))),1);
...
stp d8, d16, [fp, #0x10]	// [V18 tmp17], [V19 tmp18]
ldr q16, [fp, #0x10]	// [V04 tmp3]
ldr q17, [fp, #0x18]	// [V04 tmp3+0x08]
st2 {v16.s, v17.s}[1], [x20]
...
2. When index is not a constant
AdvSimd.StoreSelectedScalar64x2((Int32*)_dataTable.outArrayPtr,(AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)),AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr))),elemIndex);
...
mov x0, x21
movz x2, #0xC8A0 // code for System.Runtime.Intrinsics.Arm.AdvSimd:StoreSelectedScalar64x2(ulong,System.ValueTuple`2[System.Runtime.Intrinsics.Vector64`1[int],System.Runtime.Intrinsics.Vector64`1[int]],ubyte)
movk x2, #0x5DB8 LSL #16
movk x2, #0xFFFF LSL #32
ldr x2, [x2]
...
; Assembly listing for method System.Runtime.Intrinsics.Arm.AdvSimd:StoreSelectedScalar64x2(ulong,System.ValueTuple`2[System.Runtime.Intrinsics.Vector64`1[short],System.Runtime.Intrinsics.Vector64`1[short]],ubyte) (FullOpts)
G_M60890_IG01: ;; offset=0x0000
stp fp, lr, [sp, #-0x20]!
mov fp, sp
stp d0, d1, [fp, #0x10]	// [V01 arg1], [V01 arg1+0x08]
;; size=12 bbWeight=1 PerfScore 2.50
G_M60890_IG02: ;; offset=0x000C
ldr q16, [fp, #0x10]	// [V01 arg1]
ldr q17, [fp, #0x18]	// [V01 arg1+0x08]
uxtb w1, w1
adr x2, [G_M60890_IG03]
add x2, x2, x1, LSL #3
br x2
;; size=24 bbWeight=1 PerfScore 7.00
G_M60890_IG03: ;; offset=0x0024
st2 {v16.h, v17.h}[0], [x0]
b G_M60890_IG07
;; size=8 bbWeight=1 PerfScore 2.00
G_M60890_IG04: ;; offset=0x002C
st2 {v16.h, v17.h}[1], [x0]
b G_M60890_IG07
;; size=8 bbWeight=1 PerfScore 2.00
G_M60890_IG05: ;; offset=0x0034
st2 {v16.h, v17.h}[2], [x0]
b G_M60890_IG07
;; size=8 bbWeight=1 PerfScore 2.00
G_M60890_IG06: ;; offset=0x003C
st2 {v16.h, v17.h}[3], [x0]
;; size=4 bbWeight=1 PerfScore 1.00
G_M60890_IG07: ;; offset=0x0040
ldp fp, lr, [sp], #0x20
ret lr
;; size=8 bbWeight=1 PerfScore 2.00
3. When the index is variable and out of bounds The current test crashes with an error.
Illegal instruction (core dumped)

Not sure whether it's the desired behaviour. Also, I haven't considered the possibility of creating a ROP gadget with the sequence for Case 2 above. The sequence of instruction where value of an index can be used control the jump target.

@kunalspathak

Copy link
Copy Markdown
Contributor

As seen in #93197, the API names should be just StoreSelectedScalar because you can deduce the shape and tuple size from the parameters.

@kunalspathakkunalspathak left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I will double check about the immediate operand out of range scenario.

Comment threadsrc/coreclr/jit/emitarm64.cpp Outdated
Comment threadsrc/coreclr/jit/hwintrinsicarm64.cpp Outdated
Comment threadsrc/coreclr/jit/hwintrinsicarm64.cpp Outdated
Comment threadsrc/coreclr/jit/hwintrinsiclistarm64.h Outdated
Comment threadsrc/coreclr/jit/hwintrinsiclistarm64.h Outdated
@ghostghost added the needs-author-action An issue or pull request that requires more info or actions from the author. label Oct 9, 2023
@kunalspathak

Copy link
Copy Markdown
Contributor

I will double check about the immediate operand out of range scenario.

Alright, so if you follow #93197, the immOp is handled in it.

@kunalspathak

Copy link
Copy Markdown
Contributor
  1. When the index is variable and out of bounds

They should throw IndexOutOfBoundException

@ghostghost removed the needs-author-action An issue or pull request that requires more info or actions from the author. label Oct 16, 2023
@SwapnilGaikwadSwapnilGaikwad changed the title Implement StoreSelectedScalarNx2 for Arm64Implement StoreSelectedScalar for Arm64Oct 16, 2023
Comment threadsrc/coreclr/jit/hwintrinsic.cpp Outdated
Comment threadsrc/coreclr/jit/lsraarm64.cpp
Comment threadsrc/coreclr/jit/hwintrinsiclistarm64.h Outdated
Comment threadsrc/coreclr/jit/hwintrinsiccodegenarm64.cpp Outdated
Comment threadsrc/coreclr/jit/emitarm64.cpp
Comment threadsrc/coreclr/jit/hwintrinsic.cpp Outdated
@ghostghost added needs-author-action An issue or pull request that requires more info or actions from the author. and removed needs-author-action An issue or pull request that requires more info or actions from the author. labels Oct 16, 2023
@kunalspathak

Copy link
Copy Markdown
Contributor

RunBasicScenario_UnsafeRead segfaults with the following error

Interesting. What is the cause of it?

@SwapnilGaikwad

Copy link
Copy Markdown
ContributorAuthor

Now we get out of range exception for all the invalid scenarios (with constant or variable index) with all the test cases.

System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values.

I never got to ensure from the assembly that it throws InvalidIndexException. 🤔

This mystery is also resolved now. There was a check for array out of bounds missing. Now added it. Can be confirmed from the assembly for StoreSelectedScalar as well.

...
G_M56847_IG04:
ldr x0, [fp, #0x38]	// [V00 arg0]
ldr q16, [fp, #0x20]	// [V01 arg1]
ldr w1, [fp, #0x1C]	// [V02 arg2]
uxtb w1, w1
cmp w1, #4
blo G_M56847_IG05
bl CORINFO_HELP_THROW_ARGUMENTOUTOFRANGEEXCEPTION
...
Full assembly
; Assembly listing for method System.Runtime.Intrinsics.Arm.AdvSimd:StoreSelectedScalar(ulong,System.Runtime.Intrinsics.Vector128`1[int],ubyte) (MinOpts)
; Emitting BLENDED_CODE for generic ARM64 - Unix
; MinOpts code
; debuggable code
; fp based frame
; fully interruptible
; No PGO data
; Final local variable assignments
;
; V00 arg0 [V00 ] ( 1, 1 ) long -> [fp+0x38] do-not-enreg[]
; V01 arg1 [V01 ] ( 1, 1 ) simd16 -> [fp+0x20] HFA(simd16) do-not-enreg[S] <System.Runtime.Intrinsics.Vector128`1[int]>
; V02 arg2 [V02 ] ( 1, 1 ) ubyte -> [fp+0x1C] do-not-enreg[]
;# V03 OutArgs [V03 ] ( 1, 1 ) struct ( 0) [sp+0x00] do-not-enreg[XS] addr-exposed "OutgoingArgSpace"
;
; Lcl frame size = 48
G_M56847_IG01: ;; offset=0x0000
stp fp, lr, [sp, #-0x40]!
mov fp, sp
str x0, [fp, #0x38]	// [V00 arg0]
str w1, [fp, #0x1C]	// [V02 arg2]
str q0, [fp, #0x20]	// [V01 arg1]
;; size=20 bbWeight=1 PerfScore 4.50
G_M56847_IG02: ;; offset=0x0014
movz x0, #0x45A8
movk x0, #0x4004 LSL #16
movk x0, #0xFFFF LSL #32
ldr w0, [x0]
cbz w0, G_M56847_IG04
;; size=20 bbWeight=1 PerfScore 5.50
G_M56847_IG03: ;; offset=0x0028
bl CORINFO_HELP_DBG_IS_JUST_MY_CODE
;; size=4 bbWeight=0.50 PerfScore 0.50
G_M56847_IG04: ;; offset=0x002C
ldr x0, [fp, #0x38]	// [V00 arg0]
ldr q16, [fp, #0x20]	// [V01 arg1]
ldr w1, [fp, #0x1C]	// [V02 arg2]
uxtb w1, w1
cmp w1, #4
blo G_M56847_IG05
bl CORINFO_HELP_THROW_ARGUMENTOUTOFRANGEEXCEPTION
;; size=28 bbWeight=1 PerfScore 9.00
G_M56847_IG05: ;; offset=0x0048
ldr w1, [fp, #0x1C]	// [V02 arg2]
uxtb w1, w1
adr x2, [G_M56847_IG06]
add x2, x2, x1, LSL #3
br x2
;; size=20 bbWeight=1 PerfScore 5.00
G_M56847_IG06: ;; offset=0x005C
st1 {v16.s}[0], [x0]
b G_M56847_IG10
;; size=8 bbWeight=1 PerfScore 2.00
G_M56847_IG07: ;; offset=0x0064
st1 {v16.s}[1], [x0]
b G_M56847_IG10
;; size=8 bbWeight=1 PerfScore 2.00
G_M56847_IG08: ;; offset=0x006C
st1 {v16.s}[2], [x0]
b G_M56847_IG10
;; size=8 bbWeight=1 PerfScore 2.00
G_M56847_IG09: ;; offset=0x0074
st1 {v16.s}[3], [x0]
;; size=4 bbWeight=1 PerfScore 1.00
G_M56847_IG10: ;; offset=0x0078
nop
nop
;; size=8 bbWeight=1 PerfScore 1.00
G_M56847_IG11: ;; offset=0x0080
ldp fp, lr, [sp], #0x40
ret lr
;; size=8 bbWeight=1 PerfScore 2.00
; Total bytes of code 136, prolog size 20, PerfScore 48.10, instruction count 34, allocated bytes for code 136 (MethodHash=5b1221f0) for method System.Runtime.Intrinsics.Arm.AdvSimd:StoreSelectedScalar(ulong,System.Runtime.Intrinsics.Vector128`1[int],ubyte) (MinOpts)
; ============================================================

Interestingly, for some tests I got IndexOutOfRangeException earlier because the test was executing without an error but failing in the validation stage where it was accessing the out of range index. Only the first test was failing with an illegal instruction probably because of the code layout. Invalid index tried to jump to location that did not contain a valid index. For the further tests, the jump target at invalid index contained a valid instruction so it did not throw any exception during the execution.

@kunalspathak

Copy link
Copy Markdown
Contributor

Seems the indices of few test cases needs adjustment for them to not throw Exception.

@SwapnilGaikwad

SwapnilGaikwad commented Nov 2, 2023

Copy link
Copy Markdown
ContributorAuthor

Seems the indices of few test cases needs adjustment for them to not throw Exception.

Had to move the range check after recomputing the simdSize 🤦 . Now the current failures seems while sending the test data to helix system.

Comment threadsrc/coreclr/jit/hwintrinsicarm64.cpp Outdated
@SwapnilGaikwad

Copy link
Copy Markdown
ContributorAuthor

can you double check?

Sure! It's tricky to debug, and it isn't obvious why compilation of System.Runtime.Serialization.SerializationGuard would fail. I'll try rebasing/merging main, if the error persists then can debug further.

@kunalspathak

Copy link
Copy Markdown
Contributor

can you double check?

Sure! It's tricky to debug, and it isn't obvious why compilation of System.Runtime.Serialization.SerializationGuard would fail. I'll try rebasing/merging main, if the error persists then can debug further.

From what I remember, these tests were passing earlier and failing with the recent commit and are in arm64, so most likly related. I could be wrong.

@SwapnilGaikwad

Copy link
Copy Markdown
ContributorAuthor

can you double check?

Sure! It's tricky to debug, and it isn't obvious why compilation of System.Runtime.Serialization.SerializationGuard would fail. I'll try rebasing/merging main, if the error persists then can debug further.

From what I remember, these tests were passing earlier and failing with the recent commit and are in arm64, so most likly related. I could be wrong.

You're right, it seems to be related to the arg check. Not sure how to debug it though. I'll try to see if I can reproduce the failure. If that doesn't progress, should I put the explicit check as before?

@kunalspathak

kunalspathak commented Nov 6, 2023

Copy link
Copy Markdown
Contributor

If that doesn't progress, should I put the explicit check as before?

I would say just inspect the code changes and see if the code path for existing SelectedScalar with single vector is unchanged. That should fix the problem.

@kunalspathak

Copy link
Copy Markdown
Contributor

@SwapnilGaikwad - can you resolve the merge conflicts?

@fanyang-monofanyang-mono left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The change to Mono codebase looks good to me.

Change-Id: I81d386adbbcc195b777f436329f24438b0cca10c
@kunalspathak

Copy link
Copy Markdown
Contributor

The change to Mono codebase looks good to me.

@fanyang-mono - was the change essentially to make sure that mono continue to ignore newer APIs whose 2nd parameter is tuple and only support the existing StoreSelectedScalar API?

@fanyang-mono

fanyang-mono commented Nov 16, 2023

Copy link
Copy Markdown
Member

The change to Mono codebase looks good to me.

@fanyang-mono - was the change essentially to make sure that mono continue to ignore newer APIs whose 2nd parameter is tuple and only support the existing StoreSelectedScalar API?

Unfortunately, yes, Mono is not super friendly with handling API with 4 and more input arguments. We need to add additional code to handle those cases, rather than automatically handled by the machinery like Vector64/128. There is an issue to track Mono side of the work related to these new set of API's.

@kunalspathak
kunalspathak merged commit 2e912a3 into dotnet:mainNov 16, 2023
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Dec 17, 2023
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 SuperPMIcommunity-contributionIndicates that the PR has been added by a community membernew-api-needs-documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@SwapnilGaikwad@kunalspathak@fanyang-mono
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n 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;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Implement StoreSelectedScalar for Arm64 - #93223

Merged
kunalspathak merged 24 commits into
dotnet:mainfrom
SwapnilGaikwad:github-st2-indexed
Nov 16, 2023
Merged

Implement StoreSelectedScalar for Arm64#93223
kunalspathak merged 24 commits into
dotnet:mainfrom
SwapnilGaikwad:github-st2-indexed

Conversation

@SwapnilGaikwad

@SwapnilGaikwadSwapnilGaikwad commented Oct 9, 2023

Copy link
Copy Markdown
Contributor

Contribute towards #84510.

// AdvSimd// ST2 (single structure)publicstaticunsafevoidStoreSelectedScalar64x2(byte*address,(Vector64<byte>Value1,Vector64<byte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(sbyte*address,(Vector64<sbyte>Value1,Vector64<sbyte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(short*address,(Vector64<short>Value1,Vector64<short>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(ushort*address,(Vector64<ushort>Value1,Vector64<ushort>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(int*address,(Vector64<int>Value1,Vector64<int>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(uint*address,(Vector64<uint>Value1,Vector64<uint>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(float*address,(Vector64<float>Value1,Vector64<float>Value2)value,byteindex);// ST3 (single structure)publicstaticunsafevoidStoreSelectedScalar64x3(byte*address,(Vector64<byte>Value1,Vector64<byte>Value2,Vector64<byte>Value3)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x3(sbyte*address,(Vector64<sbyte>Value1,Vector64<sbyte>Value2,Vector64<sbyte>Value3)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x3(short*address,(Vector64<short>Value1,Vector64<short>Value2,Vector64<short>Value3)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x3(ushort*address,(Vector64<ushort>Value1,Vector64<ushort>Value2,Vector64<ushort>Value3)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x3(int*address,(Vector64<int>Value1,Vector64<int>Value2,Vector64<int>Value3)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x3(uint*address,(Vector64<uint>Value1,Vector64<uint>Value2,Vector64<uint>Value3)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x3(float*address,(Vector64<float>Value1,Vector64<float>Value2,Vector64<float>Value3)value,byteindex);// ST4 (single structure)publicstaticunsafevoidStoreSelectedScalar64x4(byte*address,(Vector64<byte>Value1,Vector64<byte>Value2,Vector64<byte>Value3,Vector64<byte>Value4)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x4(sbyte*address,(Vector64<sbyte>Value1,Vector64<sbyte>Value2,Vector64<sbyte>Value3,Vector64<sbyte>Value4)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x4(short*address,(Vector64<short>Value1,Vector64<short>Value2,Vector64<short>Value3,Vector64<short>Value4)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x4(ushort*address,(Vector64<ushort>Value1,Vector64<ushort>Value2,Vector64<ushort>Value3,Vector64<ushort>Value4)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x4(int*address,(Vector64<int>Value1,Vector64<int>Value2,Vector64<int>Value3,Vector64<int>Value4)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x4(uint*address,(Vector64<uint>Value1,Vector64<uint>Value2,Vector64<uint>Value3,Vector64<uint>Value4)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x4(float*address,(Vector64<float>Value1,Vector64<float>Value2,Vector64<float>Value3,Vector64<float>Value4)value,byteindex);// AdvSimd.Arm64// ST2 (single structure)publicstaticunsafevoidStoreSelectedScalar128x2(byte*address,(Vector128<byte>Value1,Vector128<byte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(sbyte*address,(Vector128<sbyte>Value1,Vector128<sbyte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(short*address,(Vector128<short>Value1,Vector128<short>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(ushort*address,(Vector128<ushort>Value1,Vector128<ushort>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(int*address,(Vector128<int>Value1,Vector128<int>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(uint*address,(Vector128<uint>Value1,Vector128<uint>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(long*address,(Vector128<long>Value1,Vector128<long>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(ulong*address,(Vector128<ulong>Value1,Vector128<ulong>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(float*address,(Vector128<float>Value1,Vector128<float>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(double*address,(Vector128<double>Value1,Vector128<double>Value2)value,byteindex);// ST3 (single structure)publicstaticunsafevoidStoreSelectedScalar128x3(byte*address,(Vector128<byte>Value1,Vector128<byte>Value2,Vector128<byte>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(sbyte*address,(Vector128<sbyte>Value1,Vector128<sbyte>Value2,Vector128<sbyte>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(short*address,(Vector128<short>Value1,Vector128<short>Value2,Vector128<short>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(ushort*address,(Vector128<ushort>Value1,Vector128<ushort>Value2,Vector128<ushort>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(int*address,(Vector128<int>Value1,Vector128<int>Value2,Vector128<int>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(uint*address,(Vector128<uint>Value1,Vector128<uint>Value2,Vector128<uint>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(long*address,(Vector128<long>Value1,Vector128<long>Value2,Vector128<long>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(ulong*address,(Vector128<ulong>Value1,Vector128<ulong>Value2,Vector128<ulong>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(float*address,(Vector128<float>Value1,Vector128<float>Value2,Vector128<float>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(double*address,(Vector128<double>Value1,Vector128<double>Value2,Vector128<double>Value3),byteindex);// ST4 (single structure)publicstaticunsafevoidStoreSelectedScalar128x4(byte*address,(Vector128<byte>Value1,Vector128<byte>Value2,Vector128<byte>Value3,Vector128<byte>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(sbyte*address,(Vector128<sbyte>Value1,Vector128<sbyte>Value2,Vector128<sbyte>Value3,Vector128<sbyte>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(short*address,(Vector128<short>Value1,Vector128<short>Value2,Vector128<short>Value3,Vector128<short>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(ushort*address,(Vector128<ushort>Value1,Vector128<ushort>Value2,Vector128<ushort>Value3,Vector128<ushort>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(int*address,(Vector128<int>Value1,Vector128<int>Value2,Vector128<int>Value3,Vector128<int>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(uint*address,(Vector128<uint>Value1,Vector128<uint>Value2,Vector128<uint>Value3,Vector128<uint>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(long*address,(Vector128<long>Value1,Vector128<long>Value2,Vector128<long>Value3,Vector128<long>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(ulong*address,(Vector128<ulong>Value1,Vector128<ulong>Value2,Vector128<ulong>Value3,Vector128<ulong>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(float*address,(Vector128<float>Value1,Vector128<float>Value2,Vector128<float>Value3,Vector128<float>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(double*address,(Vector128<double>Value1,Vector128<double>Value2,Vector128<double>Value3,Vector128<double>Value4),byteindex);

@ghostghost added community-contribution Indicates that the PR has been added by a community member area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI new-api-needs-documentation labels Oct 9, 2023
@ghost

ghost commented Oct 9, 2023

Copy link
Copy Markdown

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

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

@ghost

ghost commented Oct 9, 2023

Copy link
Copy Markdown

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

Issue Details

Contribute towards #84510.

// AdvSimdpublicstaticunsafevoidStoreSelectedScalar64x2(byte*address,(Vector64<byte>Value1,Vector64<byte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(sbyte*address,(Vector64<sbyte>Value1,Vector64<sbyte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(short*address,(Vector64<short>Value1,Vector64<short>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(ushort*address,(Vector64<ushort>Value1,Vector64<ushort>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(int*address,(Vector64<int>Value1,Vector64<int>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(uint*address,(Vector64<uint>Value1,Vector64<uint>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(float*address,(Vector64<float>Value1,Vector64<float>Value2)value,byteindex);// AdvSimd.Arm64publicstaticunsafevoidStoreSelectedScalar128x2(byte*address,(Vector128<byte>Value1,Vector128<byte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(sbyte*address,(Vector128<sbyte>Value1,Vector128<sbyte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(short*address,(Vector128<short>Value1,Vector128<short>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(ushort*address,(Vector128<ushort>Value1,Vector128<ushort>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(int*address,(Vector128<int>Value1,Vector128<int>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(uint*address,(Vector128<uint>Value1,Vector128<uint>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(long*address,(Vector128<long>Value1,Vector128<long>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(ulong*address,(Vector128<ulong>Value1,Vector128<ulong>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(float*address,(Vector128<float>Value1,Vector128<float>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(double*address,(Vector128<double>Value1,Vector128<double>Value2)value,byteindex);
Author:SwapnilGaikwad
Assignees:-
Labels:

area-CodeGen-coreclr, new-api-needs-documentation, community-contribution

Milestone:-

@SwapnilGaikwad

Copy link
Copy Markdown
ContributorAuthor

This patch would emit the following assembly sequence

1. When the index is a constant value
AdvSimd.StoreSelectedScalar64x2((Int32*)_dataTable.outArrayPtr,(AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)),AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr))),1);
...
stp d8, d16, [fp, #0x10]	// [V18 tmp17], [V19 tmp18]
ldr q16, [fp, #0x10]	// [V04 tmp3]
ldr q17, [fp, #0x18]	// [V04 tmp3+0x08]
st2 {v16.s, v17.s}[1], [x20]
...
2. When index is not a constant
AdvSimd.StoreSelectedScalar64x2((Int32*)_dataTable.outArrayPtr,(AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)),AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr))),elemIndex);
...
mov x0, x21
movz x2, #0xC8A0 // code for System.Runtime.Intrinsics.Arm.AdvSimd:StoreSelectedScalar64x2(ulong,System.ValueTuple`2[System.Runtime.Intrinsics.Vector64`1[int],System.Runtime.Intrinsics.Vector64`1[int]],ubyte)
movk x2, #0x5DB8 LSL #16
movk x2, #0xFFFF LSL #32
ldr x2, [x2]
...
; Assembly listing for method System.Runtime.Intrinsics.Arm.AdvSimd:StoreSelectedScalar64x2(ulong,System.ValueTuple`2[System.Runtime.Intrinsics.Vector64`1[short],System.Runtime.Intrinsics.Vector64`1[short]],ubyte) (FullOpts)
G_M60890_IG01: ;; offset=0x0000
stp fp, lr, [sp, #-0x20]!
mov fp, sp
stp d0, d1, [fp, #0x10]	// [V01 arg1], [V01 arg1+0x08]
;; size=12 bbWeight=1 PerfScore 2.50
G_M60890_IG02: ;; offset=0x000C
ldr q16, [fp, #0x10]	// [V01 arg1]
ldr q17, [fp, #0x18]	// [V01 arg1+0x08]
uxtb w1, w1
adr x2, [G_M60890_IG03]
add x2, x2, x1, LSL #3
br x2
;; size=24 bbWeight=1 PerfScore 7.00
G_M60890_IG03: ;; offset=0x0024
st2 {v16.h, v17.h}[0], [x0]
b G_M60890_IG07
;; size=8 bbWeight=1 PerfScore 2.00
G_M60890_IG04: ;; offset=0x002C
st2 {v16.h, v17.h}[1], [x0]
b G_M60890_IG07
;; size=8 bbWeight=1 PerfScore 2.00
G_M60890_IG05: ;; offset=0x0034
st2 {v16.h, v17.h}[2], [x0]
b G_M60890_IG07
;; size=8 bbWeight=1 PerfScore 2.00
G_M60890_IG06: ;; offset=0x003C
st2 {v16.h, v17.h}[3], [x0]
;; size=4 bbWeight=1 PerfScore 1.00
G_M60890_IG07: ;; offset=0x0040
ldp fp, lr, [sp], #0x20
ret lr
;; size=8 bbWeight=1 PerfScore 2.00
3. When the index is variable and out of bounds The current test crashes with an error.
Illegal instruction (core dumped)

Not sure whether it's the desired behaviour. Also, I haven't considered the possibility of creating a ROP gadget with the sequence for Case 2 above. The sequence of instruction where value of an index can be used control the jump target.

@kunalspathak

Copy link
Copy Markdown
Contributor

As seen in #93197, the API names should be just StoreSelectedScalar because you can deduce the shape and tuple size from the parameters.

@kunalspathakkunalspathak left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I will double check about the immediate operand out of range scenario.

Comment threadsrc/coreclr/jit/emitarm64.cpp Outdated
Comment threadsrc/coreclr/jit/hwintrinsicarm64.cpp Outdated
Comment threadsrc/coreclr/jit/hwintrinsicarm64.cpp Outdated
Comment threadsrc/coreclr/jit/hwintrinsiclistarm64.h Outdated
Comment threadsrc/coreclr/jit/hwintrinsiclistarm64.h Outdated
@ghostghost added the needs-author-action An issue or pull request that requires more info or actions from the author. label Oct 9, 2023
@kunalspathak

Copy link
Copy Markdown
Contributor

I will double check about the immediate operand out of range scenario.

Alright, so if you follow #93197, the immOp is handled in it.

@kunalspathak

Copy link
Copy Markdown
Contributor
  1. When the index is variable and out of bounds

They should throw IndexOutOfBoundException

@ghostghost removed the needs-author-action An issue or pull request that requires more info or actions from the author. label Oct 16, 2023
@SwapnilGaikwadSwapnilGaikwad changed the title Implement StoreSelectedScalarNx2 for Arm64Implement StoreSelectedScalar for Arm64Oct 16, 2023
Comment threadsrc/coreclr/jit/hwintrinsic.cpp Outdated
Comment threadsrc/coreclr/jit/lsraarm64.cpp
Comment threadsrc/coreclr/jit/hwintrinsiclistarm64.h Outdated
Comment threadsrc/coreclr/jit/hwintrinsiccodegenarm64.cpp Outdated
Comment threadsrc/coreclr/jit/emitarm64.cpp
Comment threadsrc/coreclr/jit/hwintrinsic.cpp Outdated
@ghostghost added needs-author-action An issue or pull request that requires more info or actions from the author. and removed needs-author-action An issue or pull request that requires more info or actions from the author. labels Oct 16, 2023
@kunalspathak

Copy link
Copy Markdown
Contributor

RunBasicScenario_UnsafeRead segfaults with the following error

Interesting. What is the cause of it?

@SwapnilGaikwad

Copy link
Copy Markdown
ContributorAuthor

Now we get out of range exception for all the invalid scenarios (with constant or variable index) with all the test cases.

System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values.

I never got to ensure from the assembly that it throws InvalidIndexException. 🤔

This mystery is also resolved now. There was a check for array out of bounds missing. Now added it. Can be confirmed from the assembly for StoreSelectedScalar as well.

...
G_M56847_IG04:
ldr x0, [fp, #0x38]	// [V00 arg0]
ldr q16, [fp, #0x20]	// [V01 arg1]
ldr w1, [fp, #0x1C]	// [V02 arg2]
uxtb w1, w1
cmp w1, #4
blo G_M56847_IG05
bl CORINFO_HELP_THROW_ARGUMENTOUTOFRANGEEXCEPTION
...
Full assembly
; Assembly listing for method System.Runtime.Intrinsics.Arm.AdvSimd:StoreSelectedScalar(ulong,System.Runtime.Intrinsics.Vector128`1[int],ubyte) (MinOpts)
; Emitting BLENDED_CODE for generic ARM64 - Unix
; MinOpts code
; debuggable code
; fp based frame
; fully interruptible
; No PGO data
; Final local variable assignments
;
; V00 arg0 [V00 ] ( 1, 1 ) long -> [fp+0x38] do-not-enreg[]
; V01 arg1 [V01 ] ( 1, 1 ) simd16 -> [fp+0x20] HFA(simd16) do-not-enreg[S] <System.Runtime.Intrinsics.Vector128`1[int]>
; V02 arg2 [V02 ] ( 1, 1 ) ubyte -> [fp+0x1C] do-not-enreg[]
;# V03 OutArgs [V03 ] ( 1, 1 ) struct ( 0) [sp+0x00] do-not-enreg[XS] addr-exposed "OutgoingArgSpace"
;
; Lcl frame size = 48
G_M56847_IG01: ;; offset=0x0000
stp fp, lr, [sp, #-0x40]!
mov fp, sp
str x0, [fp, #0x38]	// [V00 arg0]
str w1, [fp, #0x1C]	// [V02 arg2]
str q0, [fp, #0x20]	// [V01 arg1]
;; size=20 bbWeight=1 PerfScore 4.50
G_M56847_IG02: ;; offset=0x0014
movz x0, #0x45A8
movk x0, #0x4004 LSL #16
movk x0, #0xFFFF LSL #32
ldr w0, [x0]
cbz w0, G_M56847_IG04
;; size=20 bbWeight=1 PerfScore 5.50
G_M56847_IG03: ;; offset=0x0028
bl CORINFO_HELP_DBG_IS_JUST_MY_CODE
;; size=4 bbWeight=0.50 PerfScore 0.50
G_M56847_IG04: ;; offset=0x002C
ldr x0, [fp, #0x38]	// [V00 arg0]
ldr q16, [fp, #0x20]	// [V01 arg1]
ldr w1, [fp, #0x1C]	// [V02 arg2]
uxtb w1, w1
cmp w1, #4
blo G_M56847_IG05
bl CORINFO_HELP_THROW_ARGUMENTOUTOFRANGEEXCEPTION
;; size=28 bbWeight=1 PerfScore 9.00
G_M56847_IG05: ;; offset=0x0048
ldr w1, [fp, #0x1C]	// [V02 arg2]
uxtb w1, w1
adr x2, [G_M56847_IG06]
add x2, x2, x1, LSL #3
br x2
;; size=20 bbWeight=1 PerfScore 5.00
G_M56847_IG06: ;; offset=0x005C
st1 {v16.s}[0], [x0]
b G_M56847_IG10
;; size=8 bbWeight=1 PerfScore 2.00
G_M56847_IG07: ;; offset=0x0064
st1 {v16.s}[1], [x0]
b G_M56847_IG10
;; size=8 bbWeight=1 PerfScore 2.00
G_M56847_IG08: ;; offset=0x006C
st1 {v16.s}[2], [x0]
b G_M56847_IG10
;; size=8 bbWeight=1 PerfScore 2.00
G_M56847_IG09: ;; offset=0x0074
st1 {v16.s}[3], [x0]
;; size=4 bbWeight=1 PerfScore 1.00
G_M56847_IG10: ;; offset=0x0078
nop
nop
;; size=8 bbWeight=1 PerfScore 1.00
G_M56847_IG11: ;; offset=0x0080
ldp fp, lr, [sp], #0x40
ret lr
;; size=8 bbWeight=1 PerfScore 2.00
; Total bytes of code 136, prolog size 20, PerfScore 48.10, instruction count 34, allocated bytes for code 136 (MethodHash=5b1221f0) for method System.Runtime.Intrinsics.Arm.AdvSimd:StoreSelectedScalar(ulong,System.Runtime.Intrinsics.Vector128`1[int],ubyte) (MinOpts)
; ============================================================

Interestingly, for some tests I got IndexOutOfRangeException earlier because the test was executing without an error but failing in the validation stage where it was accessing the out of range index. Only the first test was failing with an illegal instruction probably because of the code layout. Invalid index tried to jump to location that did not contain a valid index. For the further tests, the jump target at invalid index contained a valid instruction so it did not throw any exception during the execution.

@kunalspathak

Copy link
Copy Markdown
Contributor

Seems the indices of few test cases needs adjustment for them to not throw Exception.

@SwapnilGaikwad

SwapnilGaikwad commented Nov 2, 2023

Copy link
Copy Markdown
ContributorAuthor

Seems the indices of few test cases needs adjustment for them to not throw Exception.

Had to move the range check after recomputing the simdSize 🤦 . Now the current failures seems while sending the test data to helix system.

Comment threadsrc/coreclr/jit/hwintrinsicarm64.cpp Outdated
@SwapnilGaikwad

Copy link
Copy Markdown
ContributorAuthor

can you double check?

Sure! It's tricky to debug, and it isn't obvious why compilation of System.Runtime.Serialization.SerializationGuard would fail. I'll try rebasing/merging main, if the error persists then can debug further.

@kunalspathak

Copy link
Copy Markdown
Contributor

can you double check?

Sure! It's tricky to debug, and it isn't obvious why compilation of System.Runtime.Serialization.SerializationGuard would fail. I'll try rebasing/merging main, if the error persists then can debug further.

From what I remember, these tests were passing earlier and failing with the recent commit and are in arm64, so most likly related. I could be wrong.

@SwapnilGaikwad

Copy link
Copy Markdown
ContributorAuthor

can you double check?

Sure! It's tricky to debug, and it isn't obvious why compilation of System.Runtime.Serialization.SerializationGuard would fail. I'll try rebasing/merging main, if the error persists then can debug further.

From what I remember, these tests were passing earlier and failing with the recent commit and are in arm64, so most likly related. I could be wrong.

You're right, it seems to be related to the arg check. Not sure how to debug it though. I'll try to see if I can reproduce the failure. If that doesn't progress, should I put the explicit check as before?

@kunalspathak

kunalspathak commented Nov 6, 2023

Copy link
Copy Markdown
Contributor

If that doesn't progress, should I put the explicit check as before?

I would say just inspect the code changes and see if the code path for existing SelectedScalar with single vector is unchanged. That should fix the problem.

@kunalspathak

Copy link
Copy Markdown
Contributor

@SwapnilGaikwad - can you resolve the merge conflicts?

@fanyang-monofanyang-mono left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The change to Mono codebase looks good to me.

Change-Id: I81d386adbbcc195b777f436329f24438b0cca10c
@kunalspathak

Copy link
Copy Markdown
Contributor

The change to Mono codebase looks good to me.

@fanyang-mono - was the change essentially to make sure that mono continue to ignore newer APIs whose 2nd parameter is tuple and only support the existing StoreSelectedScalar API?

@fanyang-mono

fanyang-mono commented Nov 16, 2023

Copy link
Copy Markdown
Member

The change to Mono codebase looks good to me.

@fanyang-mono - was the change essentially to make sure that mono continue to ignore newer APIs whose 2nd parameter is tuple and only support the existing StoreSelectedScalar API?

Unfortunately, yes, Mono is not super friendly with handling API with 4 and more input arguments. We need to add additional code to handle those cases, rather than automatically handled by the machinery like Vector64/128. There is an issue to track Mono side of the work related to these new set of API's.

@kunalspathak
kunalspathak merged commit 2e912a3 into dotnet:mainNov 16, 2023
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Dec 17, 2023
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 SuperPMIcommunity-contributionIndicates that the PR has been added by a community membernew-api-needs-documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@SwapnilGaikwad@kunalspathak@fanyang-mono
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Implement StoreSelectedScalar for Arm64 - #93223

Merged
kunalspathak merged 24 commits into
dotnet:mainfrom
SwapnilGaikwad:github-st2-indexed
Nov 16, 2023
Merged

Implement StoreSelectedScalar for Arm64#93223
kunalspathak merged 24 commits into
dotnet:mainfrom
SwapnilGaikwad:github-st2-indexed

Conversation

@SwapnilGaikwad

@SwapnilGaikwadSwapnilGaikwad commented Oct 9, 2023

Copy link
Copy Markdown
Contributor

Contribute towards #84510.

// AdvSimd// ST2 (single structure)publicstaticunsafevoidStoreSelectedScalar64x2(byte*address,(Vector64<byte>Value1,Vector64<byte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(sbyte*address,(Vector64<sbyte>Value1,Vector64<sbyte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(short*address,(Vector64<short>Value1,Vector64<short>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(ushort*address,(Vector64<ushort>Value1,Vector64<ushort>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(int*address,(Vector64<int>Value1,Vector64<int>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(uint*address,(Vector64<uint>Value1,Vector64<uint>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(float*address,(Vector64<float>Value1,Vector64<float>Value2)value,byteindex);// ST3 (single structure)publicstaticunsafevoidStoreSelectedScalar64x3(byte*address,(Vector64<byte>Value1,Vector64<byte>Value2,Vector64<byte>Value3)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x3(sbyte*address,(Vector64<sbyte>Value1,Vector64<sbyte>Value2,Vector64<sbyte>Value3)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x3(short*address,(Vector64<short>Value1,Vector64<short>Value2,Vector64<short>Value3)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x3(ushort*address,(Vector64<ushort>Value1,Vector64<ushort>Value2,Vector64<ushort>Value3)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x3(int*address,(Vector64<int>Value1,Vector64<int>Value2,Vector64<int>Value3)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x3(uint*address,(Vector64<uint>Value1,Vector64<uint>Value2,Vector64<uint>Value3)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x3(float*address,(Vector64<float>Value1,Vector64<float>Value2,Vector64<float>Value3)value,byteindex);// ST4 (single structure)publicstaticunsafevoidStoreSelectedScalar64x4(byte*address,(Vector64<byte>Value1,Vector64<byte>Value2,Vector64<byte>Value3,Vector64<byte>Value4)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x4(sbyte*address,(Vector64<sbyte>Value1,Vector64<sbyte>Value2,Vector64<sbyte>Value3,Vector64<sbyte>Value4)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x4(short*address,(Vector64<short>Value1,Vector64<short>Value2,Vector64<short>Value3,Vector64<short>Value4)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x4(ushort*address,(Vector64<ushort>Value1,Vector64<ushort>Value2,Vector64<ushort>Value3,Vector64<ushort>Value4)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x4(int*address,(Vector64<int>Value1,Vector64<int>Value2,Vector64<int>Value3,Vector64<int>Value4)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x4(uint*address,(Vector64<uint>Value1,Vector64<uint>Value2,Vector64<uint>Value3,Vector64<uint>Value4)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x4(float*address,(Vector64<float>Value1,Vector64<float>Value2,Vector64<float>Value3,Vector64<float>Value4)value,byteindex);// AdvSimd.Arm64// ST2 (single structure)publicstaticunsafevoidStoreSelectedScalar128x2(byte*address,(Vector128<byte>Value1,Vector128<byte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(sbyte*address,(Vector128<sbyte>Value1,Vector128<sbyte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(short*address,(Vector128<short>Value1,Vector128<short>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(ushort*address,(Vector128<ushort>Value1,Vector128<ushort>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(int*address,(Vector128<int>Value1,Vector128<int>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(uint*address,(Vector128<uint>Value1,Vector128<uint>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(long*address,(Vector128<long>Value1,Vector128<long>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(ulong*address,(Vector128<ulong>Value1,Vector128<ulong>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(float*address,(Vector128<float>Value1,Vector128<float>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(double*address,(Vector128<double>Value1,Vector128<double>Value2)value,byteindex);// ST3 (single structure)publicstaticunsafevoidStoreSelectedScalar128x3(byte*address,(Vector128<byte>Value1,Vector128<byte>Value2,Vector128<byte>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(sbyte*address,(Vector128<sbyte>Value1,Vector128<sbyte>Value2,Vector128<sbyte>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(short*address,(Vector128<short>Value1,Vector128<short>Value2,Vector128<short>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(ushort*address,(Vector128<ushort>Value1,Vector128<ushort>Value2,Vector128<ushort>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(int*address,(Vector128<int>Value1,Vector128<int>Value2,Vector128<int>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(uint*address,(Vector128<uint>Value1,Vector128<uint>Value2,Vector128<uint>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(long*address,(Vector128<long>Value1,Vector128<long>Value2,Vector128<long>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(ulong*address,(Vector128<ulong>Value1,Vector128<ulong>Value2,Vector128<ulong>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(float*address,(Vector128<float>Value1,Vector128<float>Value2,Vector128<float>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(double*address,(Vector128<double>Value1,Vector128<double>Value2,Vector128<double>Value3),byteindex);// ST4 (single structure)publicstaticunsafevoidStoreSelectedScalar128x4(byte*address,(Vector128<byte>Value1,Vector128<byte>Value2,Vector128<byte>Value3,Vector128<byte>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(sbyte*address,(Vector128<sbyte>Value1,Vector128<sbyte>Value2,Vector128<sbyte>Value3,Vector128<sbyte>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(short*address,(Vector128<short>Value1,Vector128<short>Value2,Vector128<short>Value3,Vector128<short>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(ushort*address,(Vector128<ushort>Value1,Vector128<ushort>Value2,Vector128<ushort>Value3,Vector128<ushort>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(int*address,(Vector128<int>Value1,Vector128<int>Value2,Vector128<int>Value3,Vector128<int>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(uint*address,(Vector128<uint>Value1,Vector128<uint>Value2,Vector128<uint>Value3,Vector128<uint>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(long*address,(Vector128<long>Value1,Vector128<long>Value2,Vector128<long>Value3,Vector128<long>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(ulong*address,(Vector128<ulong>Value1,Vector128<ulong>Value2,Vector128<ulong>Value3,Vector128<ulong>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(float*address,(Vector128<float>Value1,Vector128<float>Value2,Vector128<float>Value3,Vector128<float>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(double*address,(Vector128<double>Value1,Vector128<double>Value2,Vector128<double>Value3,Vector128<double>Value4),byteindex);

@ghostghost added community-contribution Indicates that the PR has been added by a community member area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI new-api-needs-documentation labels Oct 9, 2023
@ghost

ghost commented Oct 9, 2023

Copy link
Copy Markdown

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

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

@ghost

ghost commented Oct 9, 2023

Copy link
Copy Markdown

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

Issue Details

Contribute towards #84510.

// AdvSimdpublicstaticunsafevoidStoreSelectedScalar64x2(byte*address,(Vector64<byte>Value1,Vector64<byte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(sbyte*address,(Vector64<sbyte>Value1,Vector64<sbyte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(short*address,(Vector64<short>Value1,Vector64<short>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(ushort*address,(Vector64<ushort>Value1,Vector64<ushort>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(int*address,(Vector64<int>Value1,Vector64<int>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(uint*address,(Vector64<uint>Value1,Vector64<uint>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(float*address,(Vector64<float>Value1,Vector64<float>Value2)value,byteindex);// AdvSimd.Arm64publicstaticunsafevoidStoreSelectedScalar128x2(byte*address,(Vector128<byte>Value1,Vector128<byte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(sbyte*address,(Vector128<sbyte>Value1,Vector128<sbyte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(short*address,(Vector128<short>Value1,Vector128<short>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(ushort*address,(Vector128<ushort>Value1,Vector128<ushort>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(int*address,(Vector128<int>Value1,Vector128<int>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(uint*address,(Vector128<uint>Value1,Vector128<uint>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(long*address,(Vector128<long>Value1,Vector128<long>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(ulong*address,(Vector128<ulong>Value1,Vector128<ulong>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(float*address,(Vector128<float>Value1,Vector128<float>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(double*address,(Vector128<double>Value1,Vector128<double>Value2)value,byteindex);
Author:SwapnilGaikwad
Assignees:-
Labels:

area-CodeGen-coreclr, new-api-needs-documentation, community-contribution

Milestone:-

@SwapnilGaikwad

Copy link
Copy Markdown
ContributorAuthor

This patch would emit the following assembly sequence

1. When the index is a constant value
AdvSimd.StoreSelectedScalar64x2((Int32*)_dataTable.outArrayPtr,(AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)),AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr))),1);
...
stp d8, d16, [fp, #0x10]	// [V18 tmp17], [V19 tmp18]
ldr q16, [fp, #0x10]	// [V04 tmp3]
ldr q17, [fp, #0x18]	// [V04 tmp3+0x08]
st2 {v16.s, v17.s}[1], [x20]
...
2. When index is not a constant
AdvSimd.StoreSelectedScalar64x2((Int32*)_dataTable.outArrayPtr,(AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)),AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr))),elemIndex);
...
mov x0, x21
movz x2, #0xC8A0 // code for System.Runtime.Intrinsics.Arm.AdvSimd:StoreSelectedScalar64x2(ulong,System.ValueTuple`2[System.Runtime.Intrinsics.Vector64`1[int],System.Runtime.Intrinsics.Vector64`1[int]],ubyte)
movk x2, #0x5DB8 LSL #16
movk x2, #0xFFFF LSL #32
ldr x2, [x2]
...
; Assembly listing for method System.Runtime.Intrinsics.Arm.AdvSimd:StoreSelectedScalar64x2(ulong,System.ValueTuple`2[System.Runtime.Intrinsics.Vector64`1[short],System.Runtime.Intrinsics.Vector64`1[short]],ubyte) (FullOpts)
G_M60890_IG01: ;; offset=0x0000
stp fp, lr, [sp, #-0x20]!
mov fp, sp
stp d0, d1, [fp, #0x10]	// [V01 arg1], [V01 arg1+0x08]
;; size=12 bbWeight=1 PerfScore 2.50
G_M60890_IG02: ;; offset=0x000C
ldr q16, [fp, #0x10]	// [V01 arg1]
ldr q17, [fp, #0x18]	// [V01 arg1+0x08]
uxtb w1, w1
adr x2, [G_M60890_IG03]
add x2, x2, x1, LSL #3
br x2
;; size=24 bbWeight=1 PerfScore 7.00
G_M60890_IG03: ;; offset=0x0024
st2 {v16.h, v17.h}[0], [x0]
b G_M60890_IG07
;; size=8 bbWeight=1 PerfScore 2.00
G_M60890_IG04: ;; offset=0x002C
st2 {v16.h, v17.h}[1], [x0]
b G_M60890_IG07
;; size=8 bbWeight=1 PerfScore 2.00
G_M60890_IG05: ;; offset=0x0034
st2 {v16.h, v17.h}[2], [x0]
b G_M60890_IG07
;; size=8 bbWeight=1 PerfScore 2.00
G_M60890_IG06: ;; offset=0x003C
st2 {v16.h, v17.h}[3], [x0]
;; size=4 bbWeight=1 PerfScore 1.00
G_M60890_IG07: ;; offset=0x0040
ldp fp, lr, [sp], #0x20
ret lr
;; size=8 bbWeight=1 PerfScore 2.00
3. When the index is variable and out of bounds The current test crashes with an error.
Illegal instruction (core dumped)

Not sure whether it's the desired behaviour. Also, I haven't considered the possibility of creating a ROP gadget with the sequence for Case 2 above. The sequence of instruction where value of an index can be used control the jump target.

@kunalspathak

Copy link
Copy Markdown
Contributor

As seen in #93197, the API names should be just StoreSelectedScalar because you can deduce the shape and tuple size from the parameters.

@kunalspathakkunalspathak left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I will double check about the immediate operand out of range scenario.

Comment threadsrc/coreclr/jit/emitarm64.cpp Outdated
Comment threadsrc/coreclr/jit/hwintrinsicarm64.cpp Outdated
Comment threadsrc/coreclr/jit/hwintrinsicarm64.cpp Outdated
Comment threadsrc/coreclr/jit/hwintrinsiclistarm64.h Outdated
Comment threadsrc/coreclr/jit/hwintrinsiclistarm64.h Outdated
@ghostghost added the needs-author-action An issue or pull request that requires more info or actions from the author. label Oct 9, 2023
@kunalspathak

Copy link
Copy Markdown
Contributor

I will double check about the immediate operand out of range scenario.

Alright, so if you follow #93197, the immOp is handled in it.

@kunalspathak

Copy link
Copy Markdown
Contributor
  1. When the index is variable and out of bounds

They should throw IndexOutOfBoundException

@ghostghost removed the needs-author-action An issue or pull request that requires more info or actions from the author. label Oct 16, 2023
@SwapnilGaikwadSwapnilGaikwad changed the title Implement StoreSelectedScalarNx2 for Arm64Implement StoreSelectedScalar for Arm64Oct 16, 2023
Comment threadsrc/coreclr/jit/hwintrinsic.cpp Outdated
Comment threadsrc/coreclr/jit/lsraarm64.cpp
Comment threadsrc/coreclr/jit/hwintrinsiclistarm64.h Outdated
Comment threadsrc/coreclr/jit/hwintrinsiccodegenarm64.cpp Outdated
Comment threadsrc/coreclr/jit/emitarm64.cpp
Comment threadsrc/coreclr/jit/hwintrinsic.cpp Outdated
@ghostghost added needs-author-action An issue or pull request that requires more info or actions from the author. and removed needs-author-action An issue or pull request that requires more info or actions from the author. labels Oct 16, 2023
@kunalspathak

Copy link
Copy Markdown
Contributor

RunBasicScenario_UnsafeRead segfaults with the following error

Interesting. What is the cause of it?

@SwapnilGaikwad

Copy link
Copy Markdown
ContributorAuthor

Now we get out of range exception for all the invalid scenarios (with constant or variable index) with all the test cases.

System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values.

I never got to ensure from the assembly that it throws InvalidIndexException. 🤔

This mystery is also resolved now. There was a check for array out of bounds missing. Now added it. Can be confirmed from the assembly for StoreSelectedScalar as well.

...
G_M56847_IG04:
ldr x0, [fp, #0x38]	// [V00 arg0]
ldr q16, [fp, #0x20]	// [V01 arg1]
ldr w1, [fp, #0x1C]	// [V02 arg2]
uxtb w1, w1
cmp w1, #4
blo G_M56847_IG05
bl CORINFO_HELP_THROW_ARGUMENTOUTOFRANGEEXCEPTION
...
Full assembly
; Assembly listing for method System.Runtime.Intrinsics.Arm.AdvSimd:StoreSelectedScalar(ulong,System.Runtime.Intrinsics.Vector128`1[int],ubyte) (MinOpts)
; Emitting BLENDED_CODE for generic ARM64 - Unix
; MinOpts code
; debuggable code
; fp based frame
; fully interruptible
; No PGO data
; Final local variable assignments
;
; V00 arg0 [V00 ] ( 1, 1 ) long -> [fp+0x38] do-not-enreg[]
; V01 arg1 [V01 ] ( 1, 1 ) simd16 -> [fp+0x20] HFA(simd16) do-not-enreg[S] <System.Runtime.Intrinsics.Vector128`1[int]>
; V02 arg2 [V02 ] ( 1, 1 ) ubyte -> [fp+0x1C] do-not-enreg[]
;# V03 OutArgs [V03 ] ( 1, 1 ) struct ( 0) [sp+0x00] do-not-enreg[XS] addr-exposed "OutgoingArgSpace"
;
; Lcl frame size = 48
G_M56847_IG01: ;; offset=0x0000
stp fp, lr, [sp, #-0x40]!
mov fp, sp
str x0, [fp, #0x38]	// [V00 arg0]
str w1, [fp, #0x1C]	// [V02 arg2]
str q0, [fp, #0x20]	// [V01 arg1]
;; size=20 bbWeight=1 PerfScore 4.50
G_M56847_IG02: ;; offset=0x0014
movz x0, #0x45A8
movk x0, #0x4004 LSL #16
movk x0, #0xFFFF LSL #32
ldr w0, [x0]
cbz w0, G_M56847_IG04
;; size=20 bbWeight=1 PerfScore 5.50
G_M56847_IG03: ;; offset=0x0028
bl CORINFO_HELP_DBG_IS_JUST_MY_CODE
;; size=4 bbWeight=0.50 PerfScore 0.50
G_M56847_IG04: ;; offset=0x002C
ldr x0, [fp, #0x38]	// [V00 arg0]
ldr q16, [fp, #0x20]	// [V01 arg1]
ldr w1, [fp, #0x1C]	// [V02 arg2]
uxtb w1, w1
cmp w1, #4
blo G_M56847_IG05
bl CORINFO_HELP_THROW_ARGUMENTOUTOFRANGEEXCEPTION
;; size=28 bbWeight=1 PerfScore 9.00
G_M56847_IG05: ;; offset=0x0048
ldr w1, [fp, #0x1C]	// [V02 arg2]
uxtb w1, w1
adr x2, [G_M56847_IG06]
add x2, x2, x1, LSL #3
br x2
;; size=20 bbWeight=1 PerfScore 5.00
G_M56847_IG06: ;; offset=0x005C
st1 {v16.s}[0], [x0]
b G_M56847_IG10
;; size=8 bbWeight=1 PerfScore 2.00
G_M56847_IG07: ;; offset=0x0064
st1 {v16.s}[1], [x0]
b G_M56847_IG10
;; size=8 bbWeight=1 PerfScore 2.00
G_M56847_IG08: ;; offset=0x006C
st1 {v16.s}[2], [x0]
b G_M56847_IG10
;; size=8 bbWeight=1 PerfScore 2.00
G_M56847_IG09: ;; offset=0x0074
st1 {v16.s}[3], [x0]
;; size=4 bbWeight=1 PerfScore 1.00
G_M56847_IG10: ;; offset=0x0078
nop
nop
;; size=8 bbWeight=1 PerfScore 1.00
G_M56847_IG11: ;; offset=0x0080
ldp fp, lr, [sp], #0x40
ret lr
;; size=8 bbWeight=1 PerfScore 2.00
; Total bytes of code 136, prolog size 20, PerfScore 48.10, instruction count 34, allocated bytes for code 136 (MethodHash=5b1221f0) for method System.Runtime.Intrinsics.Arm.AdvSimd:StoreSelectedScalar(ulong,System.Runtime.Intrinsics.Vector128`1[int],ubyte) (MinOpts)
; ============================================================

Interestingly, for some tests I got IndexOutOfRangeException earlier because the test was executing without an error but failing in the validation stage where it was accessing the out of range index. Only the first test was failing with an illegal instruction probably because of the code layout. Invalid index tried to jump to location that did not contain a valid index. For the further tests, the jump target at invalid index contained a valid instruction so it did not throw any exception during the execution.

@kunalspathak

Copy link
Copy Markdown
Contributor

Seems the indices of few test cases needs adjustment for them to not throw Exception.

@SwapnilGaikwad

SwapnilGaikwad commented Nov 2, 2023

Copy link
Copy Markdown
ContributorAuthor

Seems the indices of few test cases needs adjustment for them to not throw Exception.

Had to move the range check after recomputing the simdSize 🤦 . Now the current failures seems while sending the test data to helix system.

Comment threadsrc/coreclr/jit/hwintrinsicarm64.cpp Outdated
@SwapnilGaikwad

Copy link
Copy Markdown
ContributorAuthor

can you double check?

Sure! It's tricky to debug, and it isn't obvious why compilation of System.Runtime.Serialization.SerializationGuard would fail. I'll try rebasing/merging main, if the error persists then can debug further.

@kunalspathak

Copy link
Copy Markdown
Contributor

can you double check?

Sure! It's tricky to debug, and it isn't obvious why compilation of System.Runtime.Serialization.SerializationGuard would fail. I'll try rebasing/merging main, if the error persists then can debug further.

From what I remember, these tests were passing earlier and failing with the recent commit and are in arm64, so most likly related. I could be wrong.

@SwapnilGaikwad

Copy link
Copy Markdown
ContributorAuthor

can you double check?

Sure! It's tricky to debug, and it isn't obvious why compilation of System.Runtime.Serialization.SerializationGuard would fail. I'll try rebasing/merging main, if the error persists then can debug further.

From what I remember, these tests were passing earlier and failing with the recent commit and are in arm64, so most likly related. I could be wrong.

You're right, it seems to be related to the arg check. Not sure how to debug it though. I'll try to see if I can reproduce the failure. If that doesn't progress, should I put the explicit check as before?

@kunalspathak

kunalspathak commented Nov 6, 2023

Copy link
Copy Markdown
Contributor

If that doesn't progress, should I put the explicit check as before?

I would say just inspect the code changes and see if the code path for existing SelectedScalar with single vector is unchanged. That should fix the problem.

@kunalspathak

Copy link
Copy Markdown
Contributor

@SwapnilGaikwad - can you resolve the merge conflicts?

@fanyang-monofanyang-mono left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The change to Mono codebase looks good to me.

Change-Id: I81d386adbbcc195b777f436329f24438b0cca10c
@kunalspathak

Copy link
Copy Markdown
Contributor

The change to Mono codebase looks good to me.

@fanyang-mono - was the change essentially to make sure that mono continue to ignore newer APIs whose 2nd parameter is tuple and only support the existing StoreSelectedScalar API?

@fanyang-mono

fanyang-mono commented Nov 16, 2023

Copy link
Copy Markdown
Member

The change to Mono codebase looks good to me.

@fanyang-mono - was the change essentially to make sure that mono continue to ignore newer APIs whose 2nd parameter is tuple and only support the existing StoreSelectedScalar API?

Unfortunately, yes, Mono is not super friendly with handling API with 4 and more input arguments. We need to add additional code to handle those cases, rather than automatically handled by the machinery like Vector64/128. There is an issue to track Mono side of the work related to these new set of API's.

@kunalspathak
kunalspathak merged commit 2e912a3 into dotnet:mainNov 16, 2023
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Dec 17, 2023
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 SuperPMIcommunity-contributionIndicates that the PR has been added by a community membernew-api-needs-documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

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

Implement StoreSelectedScalar for Arm64 - #93223

Merged
kunalspathak merged 24 commits into
dotnet:mainfrom
SwapnilGaikwad:github-st2-indexed
Nov 16, 2023
Merged

Implement StoreSelectedScalar for Arm64#93223
kunalspathak merged 24 commits into
dotnet:mainfrom
SwapnilGaikwad:github-st2-indexed

Conversation

@SwapnilGaikwad

@SwapnilGaikwadSwapnilGaikwad commented Oct 9, 2023

Copy link
Copy Markdown
Contributor

Contribute towards #84510.

// AdvSimd// ST2 (single structure)publicstaticunsafevoidStoreSelectedScalar64x2(byte*address,(Vector64<byte>Value1,Vector64<byte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(sbyte*address,(Vector64<sbyte>Value1,Vector64<sbyte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(short*address,(Vector64<short>Value1,Vector64<short>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(ushort*address,(Vector64<ushort>Value1,Vector64<ushort>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(int*address,(Vector64<int>Value1,Vector64<int>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(uint*address,(Vector64<uint>Value1,Vector64<uint>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(float*address,(Vector64<float>Value1,Vector64<float>Value2)value,byteindex);// ST3 (single structure)publicstaticunsafevoidStoreSelectedScalar64x3(byte*address,(Vector64<byte>Value1,Vector64<byte>Value2,Vector64<byte>Value3)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x3(sbyte*address,(Vector64<sbyte>Value1,Vector64<sbyte>Value2,Vector64<sbyte>Value3)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x3(short*address,(Vector64<short>Value1,Vector64<short>Value2,Vector64<short>Value3)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x3(ushort*address,(Vector64<ushort>Value1,Vector64<ushort>Value2,Vector64<ushort>Value3)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x3(int*address,(Vector64<int>Value1,Vector64<int>Value2,Vector64<int>Value3)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x3(uint*address,(Vector64<uint>Value1,Vector64<uint>Value2,Vector64<uint>Value3)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x3(float*address,(Vector64<float>Value1,Vector64<float>Value2,Vector64<float>Value3)value,byteindex);// ST4 (single structure)publicstaticunsafevoidStoreSelectedScalar64x4(byte*address,(Vector64<byte>Value1,Vector64<byte>Value2,Vector64<byte>Value3,Vector64<byte>Value4)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x4(sbyte*address,(Vector64<sbyte>Value1,Vector64<sbyte>Value2,Vector64<sbyte>Value3,Vector64<sbyte>Value4)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x4(short*address,(Vector64<short>Value1,Vector64<short>Value2,Vector64<short>Value3,Vector64<short>Value4)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x4(ushort*address,(Vector64<ushort>Value1,Vector64<ushort>Value2,Vector64<ushort>Value3,Vector64<ushort>Value4)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x4(int*address,(Vector64<int>Value1,Vector64<int>Value2,Vector64<int>Value3,Vector64<int>Value4)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x4(uint*address,(Vector64<uint>Value1,Vector64<uint>Value2,Vector64<uint>Value3,Vector64<uint>Value4)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x4(float*address,(Vector64<float>Value1,Vector64<float>Value2,Vector64<float>Value3,Vector64<float>Value4)value,byteindex);// AdvSimd.Arm64// ST2 (single structure)publicstaticunsafevoidStoreSelectedScalar128x2(byte*address,(Vector128<byte>Value1,Vector128<byte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(sbyte*address,(Vector128<sbyte>Value1,Vector128<sbyte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(short*address,(Vector128<short>Value1,Vector128<short>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(ushort*address,(Vector128<ushort>Value1,Vector128<ushort>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(int*address,(Vector128<int>Value1,Vector128<int>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(uint*address,(Vector128<uint>Value1,Vector128<uint>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(long*address,(Vector128<long>Value1,Vector128<long>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(ulong*address,(Vector128<ulong>Value1,Vector128<ulong>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(float*address,(Vector128<float>Value1,Vector128<float>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(double*address,(Vector128<double>Value1,Vector128<double>Value2)value,byteindex);// ST3 (single structure)publicstaticunsafevoidStoreSelectedScalar128x3(byte*address,(Vector128<byte>Value1,Vector128<byte>Value2,Vector128<byte>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(sbyte*address,(Vector128<sbyte>Value1,Vector128<sbyte>Value2,Vector128<sbyte>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(short*address,(Vector128<short>Value1,Vector128<short>Value2,Vector128<short>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(ushort*address,(Vector128<ushort>Value1,Vector128<ushort>Value2,Vector128<ushort>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(int*address,(Vector128<int>Value1,Vector128<int>Value2,Vector128<int>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(uint*address,(Vector128<uint>Value1,Vector128<uint>Value2,Vector128<uint>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(long*address,(Vector128<long>Value1,Vector128<long>Value2,Vector128<long>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(ulong*address,(Vector128<ulong>Value1,Vector128<ulong>Value2,Vector128<ulong>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(float*address,(Vector128<float>Value1,Vector128<float>Value2,Vector128<float>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(double*address,(Vector128<double>Value1,Vector128<double>Value2,Vector128<double>Value3),byteindex);// ST4 (single structure)publicstaticunsafevoidStoreSelectedScalar128x4(byte*address,(Vector128<byte>Value1,Vector128<byte>Value2,Vector128<byte>Value3,Vector128<byte>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(sbyte*address,(Vector128<sbyte>Value1,Vector128<sbyte>Value2,Vector128<sbyte>Value3,Vector128<sbyte>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(short*address,(Vector128<short>Value1,Vector128<short>Value2,Vector128<short>Value3,Vector128<short>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(ushort*address,(Vector128<ushort>Value1,Vector128<ushort>Value2,Vector128<ushort>Value3,Vector128<ushort>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(int*address,(Vector128<int>Value1,Vector128<int>Value2,Vector128<int>Value3,Vector128<int>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(uint*address,(Vector128<uint>Value1,Vector128<uint>Value2,Vector128<uint>Value3,Vector128<uint>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(long*address,(Vector128<long>Value1,Vector128<long>Value2,Vector128<long>Value3,Vector128<long>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(ulong*address,(Vector128<ulong>Value1,Vector128<ulong>Value2,Vector128<ulong>Value3,Vector128<ulong>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(float*address,(Vector128<float>Value1,Vector128<float>Value2,Vector128<float>Value3,Vector128<float>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(double*address,(Vector128<double>Value1,Vector128<double>Value2,Vector128<double>Value3,Vector128<double>Value4),byteindex);

@ghostghost added community-contribution Indicates that the PR has been added by a community member area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI new-api-needs-documentation labels Oct 9, 2023
@ghost

ghost commented Oct 9, 2023

Copy link
Copy Markdown

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

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

@ghost

ghost commented Oct 9, 2023

Copy link
Copy Markdown

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

Issue Details

Contribute towards #84510.

// AdvSimdpublicstaticunsafevoidStoreSelectedScalar64x2(byte*address,(Vector64<byte>Value1,Vector64<byte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(sbyte*address,(Vector64<sbyte>Value1,Vector64<sbyte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(short*address,(Vector64<short>Value1,Vector64<short>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(ushort*address,(Vector64<ushort>Value1,Vector64<ushort>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(int*address,(Vector64<int>Value1,Vector64<int>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(uint*address,(Vector64<uint>Value1,Vector64<uint>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(float*address,(Vector64<float>Value1,Vector64<float>Value2)value,byteindex);// AdvSimd.Arm64publicstaticunsafevoidStoreSelectedScalar128x2(byte*address,(Vector128<byte>Value1,Vector128<byte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(sbyte*address,(Vector128<sbyte>Value1,Vector128<sbyte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(short*address,(Vector128<short>Value1,Vector128<short>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(ushort*address,(Vector128<ushort>Value1,Vector128<ushort>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(int*address,(Vector128<int>Value1,Vector128<int>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(uint*address,(Vector128<uint>Value1,Vector128<uint>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(long*address,(Vector128<long>Value1,Vector128<long>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(ulong*address,(Vector128<ulong>Value1,Vector128<ulong>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(float*address,(Vector128<float>Value1,Vector128<float>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(double*address,(Vector128<double>Value1,Vector128<double>Value2)value,byteindex);
Author:SwapnilGaikwad
Assignees:-
Labels:

area-CodeGen-coreclr, new-api-needs-documentation, community-contribution

Milestone:-

@SwapnilGaikwad

Copy link
Copy Markdown
ContributorAuthor

This patch would emit the following assembly sequence

1. When the index is a constant value
AdvSimd.StoreSelectedScalar64x2((Int32*)_dataTable.outArrayPtr,(AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)),AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr))),1);
...
stp d8, d16, [fp, #0x10]	// [V18 tmp17], [V19 tmp18]
ldr q16, [fp, #0x10]	// [V04 tmp3]
ldr q17, [fp, #0x18]	// [V04 tmp3+0x08]
st2 {v16.s, v17.s}[1], [x20]
...
2. When index is not a constant
AdvSimd.StoreSelectedScalar64x2((Int32*)_dataTable.outArrayPtr,(AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)),AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr))),elemIndex);
...
mov x0, x21
movz x2, #0xC8A0 // code for System.Runtime.Intrinsics.Arm.AdvSimd:StoreSelectedScalar64x2(ulong,System.ValueTuple`2[System.Runtime.Intrinsics.Vector64`1[int],System.Runtime.Intrinsics.Vector64`1[int]],ubyte)
movk x2, #0x5DB8 LSL #16
movk x2, #0xFFFF LSL #32
ldr x2, [x2]
...
; Assembly listing for method System.Runtime.Intrinsics.Arm.AdvSimd:StoreSelectedScalar64x2(ulong,System.ValueTuple`2[System.Runtime.Intrinsics.Vector64`1[short],System.Runtime.Intrinsics.Vector64`1[short]],ubyte) (FullOpts)
G_M60890_IG01: ;; offset=0x0000
stp fp, lr, [sp, #-0x20]!
mov fp, sp
stp d0, d1, [fp, #0x10]	// [V01 arg1], [V01 arg1+0x08]
;; size=12 bbWeight=1 PerfScore 2.50
G_M60890_IG02: ;; offset=0x000C
ldr q16, [fp, #0x10]	// [V01 arg1]
ldr q17, [fp, #0x18]	// [V01 arg1+0x08]
uxtb w1, w1
adr x2, [G_M60890_IG03]
add x2, x2, x1, LSL #3
br x2
;; size=24 bbWeight=1 PerfScore 7.00
G_M60890_IG03: ;; offset=0x0024
st2 {v16.h, v17.h}[0], [x0]
b G_M60890_IG07
;; size=8 bbWeight=1 PerfScore 2.00
G_M60890_IG04: ;; offset=0x002C
st2 {v16.h, v17.h}[1], [x0]
b G_M60890_IG07
;; size=8 bbWeight=1 PerfScore 2.00
G_M60890_IG05: ;; offset=0x0034
st2 {v16.h, v17.h}[2], [x0]
b G_M60890_IG07
;; size=8 bbWeight=1 PerfScore 2.00
G_M60890_IG06: ;; offset=0x003C
st2 {v16.h, v17.h}[3], [x0]
;; size=4 bbWeight=1 PerfScore 1.00
G_M60890_IG07: ;; offset=0x0040
ldp fp, lr, [sp], #0x20
ret lr
;; size=8 bbWeight=1 PerfScore 2.00
3. When the index is variable and out of bounds The current test crashes with an error.
Illegal instruction (core dumped)

Not sure whether it's the desired behaviour. Also, I haven't considered the possibility of creating a ROP gadget with the sequence for Case 2 above. The sequence of instruction where value of an index can be used control the jump target.

@kunalspathak

Copy link
Copy Markdown
Contributor

As seen in #93197, the API names should be just StoreSelectedScalar because you can deduce the shape and tuple size from the parameters.

@kunalspathakkunalspathak left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I will double check about the immediate operand out of range scenario.

Comment threadsrc/coreclr/jit/emitarm64.cpp Outdated
Comment threadsrc/coreclr/jit/hwintrinsicarm64.cpp Outdated
Comment threadsrc/coreclr/jit/hwintrinsicarm64.cpp Outdated
Comment threadsrc/coreclr/jit/hwintrinsiclistarm64.h Outdated
Comment threadsrc/coreclr/jit/hwintrinsiclistarm64.h Outdated
@ghostghost added the needs-author-action An issue or pull request that requires more info or actions from the author. label Oct 9, 2023
@kunalspathak

Copy link
Copy Markdown
Contributor

I will double check about the immediate operand out of range scenario.

Alright, so if you follow #93197, the immOp is handled in it.

@kunalspathak

Copy link
Copy Markdown
Contributor
  1. When the index is variable and out of bounds

They should throw IndexOutOfBoundException

@ghostghost removed the needs-author-action An issue or pull request that requires more info or actions from the author. label Oct 16, 2023
@SwapnilGaikwadSwapnilGaikwad changed the title Implement StoreSelectedScalarNx2 for Arm64Implement StoreSelectedScalar for Arm64Oct 16, 2023
Comment threadsrc/coreclr/jit/hwintrinsic.cpp Outdated
Comment threadsrc/coreclr/jit/lsraarm64.cpp
Comment threadsrc/coreclr/jit/hwintrinsiclistarm64.h Outdated
Comment threadsrc/coreclr/jit/hwintrinsiccodegenarm64.cpp Outdated
Comment threadsrc/coreclr/jit/emitarm64.cpp
Comment threadsrc/coreclr/jit/hwintrinsic.cpp Outdated
@ghostghost added needs-author-action An issue or pull request that requires more info or actions from the author. and removed needs-author-action An issue or pull request that requires more info or actions from the author. labels Oct 16, 2023
@kunalspathak

Copy link
Copy Markdown
Contributor

RunBasicScenario_UnsafeRead segfaults with the following error

Interesting. What is the cause of it?

@SwapnilGaikwad

Copy link
Copy Markdown
ContributorAuthor

Now we get out of range exception for all the invalid scenarios (with constant or variable index) with all the test cases.

System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values.

I never got to ensure from the assembly that it throws InvalidIndexException. 🤔

This mystery is also resolved now. There was a check for array out of bounds missing. Now added it. Can be confirmed from the assembly for StoreSelectedScalar as well.

...
G_M56847_IG04:
ldr x0, [fp, #0x38]	// [V00 arg0]
ldr q16, [fp, #0x20]	// [V01 arg1]
ldr w1, [fp, #0x1C]	// [V02 arg2]
uxtb w1, w1
cmp w1, #4
blo G_M56847_IG05
bl CORINFO_HELP_THROW_ARGUMENTOUTOFRANGEEXCEPTION
...
Full assembly
; Assembly listing for method System.Runtime.Intrinsics.Arm.AdvSimd:StoreSelectedScalar(ulong,System.Runtime.Intrinsics.Vector128`1[int],ubyte) (MinOpts)
; Emitting BLENDED_CODE for generic ARM64 - Unix
; MinOpts code
; debuggable code
; fp based frame
; fully interruptible
; No PGO data
; Final local variable assignments
;
; V00 arg0 [V00 ] ( 1, 1 ) long -> [fp+0x38] do-not-enreg[]
; V01 arg1 [V01 ] ( 1, 1 ) simd16 -> [fp+0x20] HFA(simd16) do-not-enreg[S] <System.Runtime.Intrinsics.Vector128`1[int]>
; V02 arg2 [V02 ] ( 1, 1 ) ubyte -> [fp+0x1C] do-not-enreg[]
;# V03 OutArgs [V03 ] ( 1, 1 ) struct ( 0) [sp+0x00] do-not-enreg[XS] addr-exposed "OutgoingArgSpace"
;
; Lcl frame size = 48
G_M56847_IG01: ;; offset=0x0000
stp fp, lr, [sp, #-0x40]!
mov fp, sp
str x0, [fp, #0x38]	// [V00 arg0]
str w1, [fp, #0x1C]	// [V02 arg2]
str q0, [fp, #0x20]	// [V01 arg1]
;; size=20 bbWeight=1 PerfScore 4.50
G_M56847_IG02: ;; offset=0x0014
movz x0, #0x45A8
movk x0, #0x4004 LSL #16
movk x0, #0xFFFF LSL #32
ldr w0, [x0]
cbz w0, G_M56847_IG04
;; size=20 bbWeight=1 PerfScore 5.50
G_M56847_IG03: ;; offset=0x0028
bl CORINFO_HELP_DBG_IS_JUST_MY_CODE
;; size=4 bbWeight=0.50 PerfScore 0.50
G_M56847_IG04: ;; offset=0x002C
ldr x0, [fp, #0x38]	// [V00 arg0]
ldr q16, [fp, #0x20]	// [V01 arg1]
ldr w1, [fp, #0x1C]	// [V02 arg2]
uxtb w1, w1
cmp w1, #4
blo G_M56847_IG05
bl CORINFO_HELP_THROW_ARGUMENTOUTOFRANGEEXCEPTION
;; size=28 bbWeight=1 PerfScore 9.00
G_M56847_IG05: ;; offset=0x0048
ldr w1, [fp, #0x1C]	// [V02 arg2]
uxtb w1, w1
adr x2, [G_M56847_IG06]
add x2, x2, x1, LSL #3
br x2
;; size=20 bbWeight=1 PerfScore 5.00
G_M56847_IG06: ;; offset=0x005C
st1 {v16.s}[0], [x0]
b G_M56847_IG10
;; size=8 bbWeight=1 PerfScore 2.00
G_M56847_IG07: ;; offset=0x0064
st1 {v16.s}[1], [x0]
b G_M56847_IG10
;; size=8 bbWeight=1 PerfScore 2.00
G_M56847_IG08: ;; offset=0x006C
st1 {v16.s}[2], [x0]
b G_M56847_IG10
;; size=8 bbWeight=1 PerfScore 2.00
G_M56847_IG09: ;; offset=0x0074
st1 {v16.s}[3], [x0]
;; size=4 bbWeight=1 PerfScore 1.00
G_M56847_IG10: ;; offset=0x0078
nop
nop
;; size=8 bbWeight=1 PerfScore 1.00
G_M56847_IG11: ;; offset=0x0080
ldp fp, lr, [sp], #0x40
ret lr
;; size=8 bbWeight=1 PerfScore 2.00
; Total bytes of code 136, prolog size 20, PerfScore 48.10, instruction count 34, allocated bytes for code 136 (MethodHash=5b1221f0) for method System.Runtime.Intrinsics.Arm.AdvSimd:StoreSelectedScalar(ulong,System.Runtime.Intrinsics.Vector128`1[int],ubyte) (MinOpts)
; ============================================================

Interestingly, for some tests I got IndexOutOfRangeException earlier because the test was executing without an error but failing in the validation stage where it was accessing the out of range index. Only the first test was failing with an illegal instruction probably because of the code layout. Invalid index tried to jump to location that did not contain a valid index. For the further tests, the jump target at invalid index contained a valid instruction so it did not throw any exception during the execution.

@kunalspathak

Copy link
Copy Markdown
Contributor

Seems the indices of few test cases needs adjustment for them to not throw Exception.

@SwapnilGaikwad

SwapnilGaikwad commented Nov 2, 2023

Copy link
Copy Markdown
ContributorAuthor

Seems the indices of few test cases needs adjustment for them to not throw Exception.

Had to move the range check after recomputing the simdSize 🤦 . Now the current failures seems while sending the test data to helix system.

Comment threadsrc/coreclr/jit/hwintrinsicarm64.cpp Outdated
@SwapnilGaikwad

Copy link
Copy Markdown
ContributorAuthor

can you double check?

Sure! It's tricky to debug, and it isn't obvious why compilation of System.Runtime.Serialization.SerializationGuard would fail. I'll try rebasing/merging main, if the error persists then can debug further.

@kunalspathak

Copy link
Copy Markdown
Contributor

can you double check?

Sure! It's tricky to debug, and it isn't obvious why compilation of System.Runtime.Serialization.SerializationGuard would fail. I'll try rebasing/merging main, if the error persists then can debug further.

From what I remember, these tests were passing earlier and failing with the recent commit and are in arm64, so most likly related. I could be wrong.

@SwapnilGaikwad

Copy link
Copy Markdown
ContributorAuthor

can you double check?

Sure! It's tricky to debug, and it isn't obvious why compilation of System.Runtime.Serialization.SerializationGuard would fail. I'll try rebasing/merging main, if the error persists then can debug further.

From what I remember, these tests were passing earlier and failing with the recent commit and are in arm64, so most likly related. I could be wrong.

You're right, it seems to be related to the arg check. Not sure how to debug it though. I'll try to see if I can reproduce the failure. If that doesn't progress, should I put the explicit check as before?

@kunalspathak

kunalspathak commented Nov 6, 2023

Copy link
Copy Markdown
Contributor

If that doesn't progress, should I put the explicit check as before?

I would say just inspect the code changes and see if the code path for existing SelectedScalar with single vector is unchanged. That should fix the problem.

@kunalspathak

Copy link
Copy Markdown
Contributor

@SwapnilGaikwad - can you resolve the merge conflicts?

@fanyang-monofanyang-mono left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The change to Mono codebase looks good to me.

Change-Id: I81d386adbbcc195b777f436329f24438b0cca10c
@kunalspathak

Copy link
Copy Markdown
Contributor

The change to Mono codebase looks good to me.

@fanyang-mono - was the change essentially to make sure that mono continue to ignore newer APIs whose 2nd parameter is tuple and only support the existing StoreSelectedScalar API?

@fanyang-mono

fanyang-mono commented Nov 16, 2023

Copy link
Copy Markdown
Member

The change to Mono codebase looks good to me.

@fanyang-mono - was the change essentially to make sure that mono continue to ignore newer APIs whose 2nd parameter is tuple and only support the existing StoreSelectedScalar API?

Unfortunately, yes, Mono is not super friendly with handling API with 4 and more input arguments. We need to add additional code to handle those cases, rather than automatically handled by the machinery like Vector64/128. There is an issue to track Mono side of the work related to these new set of API's.

@kunalspathak
kunalspathak merged commit 2e912a3 into dotnet:mainNov 16, 2023
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Dec 17, 2023
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 SuperPMIcommunity-contributionIndicates that the PR has been added by a community membernew-api-needs-documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@SwapnilGaikwad@kunalspathak@fanyang-mono
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Implement StoreSelectedScalar for Arm64 - #93223

Merged
kunalspathak merged 24 commits into
dotnet:mainfrom
SwapnilGaikwad:github-st2-indexed
Nov 16, 2023
Merged

Implement StoreSelectedScalar for Arm64#93223
kunalspathak merged 24 commits into
dotnet:mainfrom
SwapnilGaikwad:github-st2-indexed

Conversation

@SwapnilGaikwad

@SwapnilGaikwadSwapnilGaikwad commented Oct 9, 2023

Copy link
Copy Markdown
Contributor

Contribute towards #84510.

// AdvSimd// ST2 (single structure)publicstaticunsafevoidStoreSelectedScalar64x2(byte*address,(Vector64<byte>Value1,Vector64<byte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(sbyte*address,(Vector64<sbyte>Value1,Vector64<sbyte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(short*address,(Vector64<short>Value1,Vector64<short>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(ushort*address,(Vector64<ushort>Value1,Vector64<ushort>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(int*address,(Vector64<int>Value1,Vector64<int>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(uint*address,(Vector64<uint>Value1,Vector64<uint>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(float*address,(Vector64<float>Value1,Vector64<float>Value2)value,byteindex);// ST3 (single structure)publicstaticunsafevoidStoreSelectedScalar64x3(byte*address,(Vector64<byte>Value1,Vector64<byte>Value2,Vector64<byte>Value3)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x3(sbyte*address,(Vector64<sbyte>Value1,Vector64<sbyte>Value2,Vector64<sbyte>Value3)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x3(short*address,(Vector64<short>Value1,Vector64<short>Value2,Vector64<short>Value3)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x3(ushort*address,(Vector64<ushort>Value1,Vector64<ushort>Value2,Vector64<ushort>Value3)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x3(int*address,(Vector64<int>Value1,Vector64<int>Value2,Vector64<int>Value3)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x3(uint*address,(Vector64<uint>Value1,Vector64<uint>Value2,Vector64<uint>Value3)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x3(float*address,(Vector64<float>Value1,Vector64<float>Value2,Vector64<float>Value3)value,byteindex);// ST4 (single structure)publicstaticunsafevoidStoreSelectedScalar64x4(byte*address,(Vector64<byte>Value1,Vector64<byte>Value2,Vector64<byte>Value3,Vector64<byte>Value4)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x4(sbyte*address,(Vector64<sbyte>Value1,Vector64<sbyte>Value2,Vector64<sbyte>Value3,Vector64<sbyte>Value4)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x4(short*address,(Vector64<short>Value1,Vector64<short>Value2,Vector64<short>Value3,Vector64<short>Value4)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x4(ushort*address,(Vector64<ushort>Value1,Vector64<ushort>Value2,Vector64<ushort>Value3,Vector64<ushort>Value4)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x4(int*address,(Vector64<int>Value1,Vector64<int>Value2,Vector64<int>Value3,Vector64<int>Value4)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x4(uint*address,(Vector64<uint>Value1,Vector64<uint>Value2,Vector64<uint>Value3,Vector64<uint>Value4)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x4(float*address,(Vector64<float>Value1,Vector64<float>Value2,Vector64<float>Value3,Vector64<float>Value4)value,byteindex);// AdvSimd.Arm64// ST2 (single structure)publicstaticunsafevoidStoreSelectedScalar128x2(byte*address,(Vector128<byte>Value1,Vector128<byte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(sbyte*address,(Vector128<sbyte>Value1,Vector128<sbyte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(short*address,(Vector128<short>Value1,Vector128<short>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(ushort*address,(Vector128<ushort>Value1,Vector128<ushort>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(int*address,(Vector128<int>Value1,Vector128<int>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(uint*address,(Vector128<uint>Value1,Vector128<uint>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(long*address,(Vector128<long>Value1,Vector128<long>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(ulong*address,(Vector128<ulong>Value1,Vector128<ulong>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(float*address,(Vector128<float>Value1,Vector128<float>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(double*address,(Vector128<double>Value1,Vector128<double>Value2)value,byteindex);// ST3 (single structure)publicstaticunsafevoidStoreSelectedScalar128x3(byte*address,(Vector128<byte>Value1,Vector128<byte>Value2,Vector128<byte>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(sbyte*address,(Vector128<sbyte>Value1,Vector128<sbyte>Value2,Vector128<sbyte>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(short*address,(Vector128<short>Value1,Vector128<short>Value2,Vector128<short>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(ushort*address,(Vector128<ushort>Value1,Vector128<ushort>Value2,Vector128<ushort>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(int*address,(Vector128<int>Value1,Vector128<int>Value2,Vector128<int>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(uint*address,(Vector128<uint>Value1,Vector128<uint>Value2,Vector128<uint>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(long*address,(Vector128<long>Value1,Vector128<long>Value2,Vector128<long>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(ulong*address,(Vector128<ulong>Value1,Vector128<ulong>Value2,Vector128<ulong>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(float*address,(Vector128<float>Value1,Vector128<float>Value2,Vector128<float>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(double*address,(Vector128<double>Value1,Vector128<double>Value2,Vector128<double>Value3),byteindex);// ST4 (single structure)publicstaticunsafevoidStoreSelectedScalar128x4(byte*address,(Vector128<byte>Value1,Vector128<byte>Value2,Vector128<byte>Value3,Vector128<byte>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(sbyte*address,(Vector128<sbyte>Value1,Vector128<sbyte>Value2,Vector128<sbyte>Value3,Vector128<sbyte>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(short*address,(Vector128<short>Value1,Vector128<short>Value2,Vector128<short>Value3,Vector128<short>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(ushort*address,(Vector128<ushort>Value1,Vector128<ushort>Value2,Vector128<ushort>Value3,Vector128<ushort>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(int*address,(Vector128<int>Value1,Vector128<int>Value2,Vector128<int>Value3,Vector128<int>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(uint*address,(Vector128<uint>Value1,Vector128<uint>Value2,Vector128<uint>Value3,Vector128<uint>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(long*address,(Vector128<long>Value1,Vector128<long>Value2,Vector128<long>Value3,Vector128<long>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(ulong*address,(Vector128<ulong>Value1,Vector128<ulong>Value2,Vector128<ulong>Value3,Vector128<ulong>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(float*address,(Vector128<float>Value1,Vector128<float>Value2,Vector128<float>Value3,Vector128<float>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(double*address,(Vector128<double>Value1,Vector128<double>Value2,Vector128<double>Value3,Vector128<double>Value4),byteindex);

@ghostghost added community-contribution Indicates that the PR has been added by a community member area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI new-api-needs-documentation labels Oct 9, 2023
@ghost

ghost commented Oct 9, 2023

Copy link
Copy Markdown

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

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

@ghost

ghost commented Oct 9, 2023

Copy link
Copy Markdown

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

Issue Details

Contribute towards #84510.

// AdvSimdpublicstaticunsafevoidStoreSelectedScalar64x2(byte*address,(Vector64<byte>Value1,Vector64<byte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(sbyte*address,(Vector64<sbyte>Value1,Vector64<sbyte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(short*address,(Vector64<short>Value1,Vector64<short>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(ushort*address,(Vector64<ushort>Value1,Vector64<ushort>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(int*address,(Vector64<int>Value1,Vector64<int>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(uint*address,(Vector64<uint>Value1,Vector64<uint>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(float*address,(Vector64<float>Value1,Vector64<float>Value2)value,byteindex);// AdvSimd.Arm64publicstaticunsafevoidStoreSelectedScalar128x2(byte*address,(Vector128<byte>Value1,Vector128<byte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(sbyte*address,(Vector128<sbyte>Value1,Vector128<sbyte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(short*address,(Vector128<short>Value1,Vector128<short>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(ushort*address,(Vector128<ushort>Value1,Vector128<ushort>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(int*address,(Vector128<int>Value1,Vector128<int>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(uint*address,(Vector128<uint>Value1,Vector128<uint>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(long*address,(Vector128<long>Value1,Vector128<long>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(ulong*address,(Vector128<ulong>Value1,Vector128<ulong>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(float*address,(Vector128<float>Value1,Vector128<float>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(double*address,(Vector128<double>Value1,Vector128<double>Value2)value,byteindex);
Author:SwapnilGaikwad
Assignees:-
Labels:

area-CodeGen-coreclr, new-api-needs-documentation, community-contribution

Milestone:-

@SwapnilGaikwad

Copy link
Copy Markdown
ContributorAuthor

This patch would emit the following assembly sequence

1. When the index is a constant value
AdvSimd.StoreSelectedScalar64x2((Int32*)_dataTable.outArrayPtr,(AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)),AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr))),1);
...
stp d8, d16, [fp, #0x10]	// [V18 tmp17], [V19 tmp18]
ldr q16, [fp, #0x10]	// [V04 tmp3]
ldr q17, [fp, #0x18]	// [V04 tmp3+0x08]
st2 {v16.s, v17.s}[1], [x20]
...
2. When index is not a constant
AdvSimd.StoreSelectedScalar64x2((Int32*)_dataTable.outArrayPtr,(AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)),AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr))),elemIndex);
...
mov x0, x21
movz x2, #0xC8A0 // code for System.Runtime.Intrinsics.Arm.AdvSimd:StoreSelectedScalar64x2(ulong,System.ValueTuple`2[System.Runtime.Intrinsics.Vector64`1[int],System.Runtime.Intrinsics.Vector64`1[int]],ubyte)
movk x2, #0x5DB8 LSL #16
movk x2, #0xFFFF LSL #32
ldr x2, [x2]
...
; Assembly listing for method System.Runtime.Intrinsics.Arm.AdvSimd:StoreSelectedScalar64x2(ulong,System.ValueTuple`2[System.Runtime.Intrinsics.Vector64`1[short],System.Runtime.Intrinsics.Vector64`1[short]],ubyte) (FullOpts)
G_M60890_IG01: ;; offset=0x0000
stp fp, lr, [sp, #-0x20]!
mov fp, sp
stp d0, d1, [fp, #0x10]	// [V01 arg1], [V01 arg1+0x08]
;; size=12 bbWeight=1 PerfScore 2.50
G_M60890_IG02: ;; offset=0x000C
ldr q16, [fp, #0x10]	// [V01 arg1]
ldr q17, [fp, #0x18]	// [V01 arg1+0x08]
uxtb w1, w1
adr x2, [G_M60890_IG03]
add x2, x2, x1, LSL #3
br x2
;; size=24 bbWeight=1 PerfScore 7.00
G_M60890_IG03: ;; offset=0x0024
st2 {v16.h, v17.h}[0], [x0]
b G_M60890_IG07
;; size=8 bbWeight=1 PerfScore 2.00
G_M60890_IG04: ;; offset=0x002C
st2 {v16.h, v17.h}[1], [x0]
b G_M60890_IG07
;; size=8 bbWeight=1 PerfScore 2.00
G_M60890_IG05: ;; offset=0x0034
st2 {v16.h, v17.h}[2], [x0]
b G_M60890_IG07
;; size=8 bbWeight=1 PerfScore 2.00
G_M60890_IG06: ;; offset=0x003C
st2 {v16.h, v17.h}[3], [x0]
;; size=4 bbWeight=1 PerfScore 1.00
G_M60890_IG07: ;; offset=0x0040
ldp fp, lr, [sp], #0x20
ret lr
;; size=8 bbWeight=1 PerfScore 2.00
3. When the index is variable and out of bounds The current test crashes with an error.
Illegal instruction (core dumped)

Not sure whether it's the desired behaviour. Also, I haven't considered the possibility of creating a ROP gadget with the sequence for Case 2 above. The sequence of instruction where value of an index can be used control the jump target.

@kunalspathak

Copy link
Copy Markdown
Contributor

As seen in #93197, the API names should be just StoreSelectedScalar because you can deduce the shape and tuple size from the parameters.

@kunalspathakkunalspathak left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I will double check about the immediate operand out of range scenario.

Comment threadsrc/coreclr/jit/emitarm64.cpp Outdated
Comment threadsrc/coreclr/jit/hwintrinsicarm64.cpp Outdated
Comment threadsrc/coreclr/jit/hwintrinsicarm64.cpp Outdated
Comment threadsrc/coreclr/jit/hwintrinsiclistarm64.h Outdated
Comment threadsrc/coreclr/jit/hwintrinsiclistarm64.h Outdated
@ghostghost added the needs-author-action An issue or pull request that requires more info or actions from the author. label Oct 9, 2023
@kunalspathak

Copy link
Copy Markdown
Contributor

I will double check about the immediate operand out of range scenario.

Alright, so if you follow #93197, the immOp is handled in it.

@kunalspathak

Copy link
Copy Markdown
Contributor
  1. When the index is variable and out of bounds

They should throw IndexOutOfBoundException

@ghostghost removed the needs-author-action An issue or pull request that requires more info or actions from the author. label Oct 16, 2023
@SwapnilGaikwadSwapnilGaikwad changed the title Implement StoreSelectedScalarNx2 for Arm64Implement StoreSelectedScalar for Arm64Oct 16, 2023
Comment threadsrc/coreclr/jit/hwintrinsic.cpp Outdated
Comment threadsrc/coreclr/jit/lsraarm64.cpp
Comment threadsrc/coreclr/jit/hwintrinsiclistarm64.h Outdated
Comment threadsrc/coreclr/jit/hwintrinsiccodegenarm64.cpp Outdated
Comment threadsrc/coreclr/jit/emitarm64.cpp
Comment threadsrc/coreclr/jit/hwintrinsic.cpp Outdated
@ghostghost added needs-author-action An issue or pull request that requires more info or actions from the author. and removed needs-author-action An issue or pull request that requires more info or actions from the author. labels Oct 16, 2023
@kunalspathak

Copy link
Copy Markdown
Contributor

RunBasicScenario_UnsafeRead segfaults with the following error

Interesting. What is the cause of it?

@SwapnilGaikwad

Copy link
Copy Markdown
ContributorAuthor

Now we get out of range exception for all the invalid scenarios (with constant or variable index) with all the test cases.

System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values.

I never got to ensure from the assembly that it throws InvalidIndexException. 🤔

This mystery is also resolved now. There was a check for array out of bounds missing. Now added it. Can be confirmed from the assembly for StoreSelectedScalar as well.

...
G_M56847_IG04:
ldr x0, [fp, #0x38]	// [V00 arg0]
ldr q16, [fp, #0x20]	// [V01 arg1]
ldr w1, [fp, #0x1C]	// [V02 arg2]
uxtb w1, w1
cmp w1, #4
blo G_M56847_IG05
bl CORINFO_HELP_THROW_ARGUMENTOUTOFRANGEEXCEPTION
...
Full assembly
; Assembly listing for method System.Runtime.Intrinsics.Arm.AdvSimd:StoreSelectedScalar(ulong,System.Runtime.Intrinsics.Vector128`1[int],ubyte) (MinOpts)
; Emitting BLENDED_CODE for generic ARM64 - Unix
; MinOpts code
; debuggable code
; fp based frame
; fully interruptible
; No PGO data
; Final local variable assignments
;
; V00 arg0 [V00 ] ( 1, 1 ) long -> [fp+0x38] do-not-enreg[]
; V01 arg1 [V01 ] ( 1, 1 ) simd16 -> [fp+0x20] HFA(simd16) do-not-enreg[S] <System.Runtime.Intrinsics.Vector128`1[int]>
; V02 arg2 [V02 ] ( 1, 1 ) ubyte -> [fp+0x1C] do-not-enreg[]
;# V03 OutArgs [V03 ] ( 1, 1 ) struct ( 0) [sp+0x00] do-not-enreg[XS] addr-exposed "OutgoingArgSpace"
;
; Lcl frame size = 48
G_M56847_IG01: ;; offset=0x0000
stp fp, lr, [sp, #-0x40]!
mov fp, sp
str x0, [fp, #0x38]	// [V00 arg0]
str w1, [fp, #0x1C]	// [V02 arg2]
str q0, [fp, #0x20]	// [V01 arg1]
;; size=20 bbWeight=1 PerfScore 4.50
G_M56847_IG02: ;; offset=0x0014
movz x0, #0x45A8
movk x0, #0x4004 LSL #16
movk x0, #0xFFFF LSL #32
ldr w0, [x0]
cbz w0, G_M56847_IG04
;; size=20 bbWeight=1 PerfScore 5.50
G_M56847_IG03: ;; offset=0x0028
bl CORINFO_HELP_DBG_IS_JUST_MY_CODE
;; size=4 bbWeight=0.50 PerfScore 0.50
G_M56847_IG04: ;; offset=0x002C
ldr x0, [fp, #0x38]	// [V00 arg0]
ldr q16, [fp, #0x20]	// [V01 arg1]
ldr w1, [fp, #0x1C]	// [V02 arg2]
uxtb w1, w1
cmp w1, #4
blo G_M56847_IG05
bl CORINFO_HELP_THROW_ARGUMENTOUTOFRANGEEXCEPTION
;; size=28 bbWeight=1 PerfScore 9.00
G_M56847_IG05: ;; offset=0x0048
ldr w1, [fp, #0x1C]	// [V02 arg2]
uxtb w1, w1
adr x2, [G_M56847_IG06]
add x2, x2, x1, LSL #3
br x2
;; size=20 bbWeight=1 PerfScore 5.00
G_M56847_IG06: ;; offset=0x005C
st1 {v16.s}[0], [x0]
b G_M56847_IG10
;; size=8 bbWeight=1 PerfScore 2.00
G_M56847_IG07: ;; offset=0x0064
st1 {v16.s}[1], [x0]
b G_M56847_IG10
;; size=8 bbWeight=1 PerfScore 2.00
G_M56847_IG08: ;; offset=0x006C
st1 {v16.s}[2], [x0]
b G_M56847_IG10
;; size=8 bbWeight=1 PerfScore 2.00
G_M56847_IG09: ;; offset=0x0074
st1 {v16.s}[3], [x0]
;; size=4 bbWeight=1 PerfScore 1.00
G_M56847_IG10: ;; offset=0x0078
nop
nop
;; size=8 bbWeight=1 PerfScore 1.00
G_M56847_IG11: ;; offset=0x0080
ldp fp, lr, [sp], #0x40
ret lr
;; size=8 bbWeight=1 PerfScore 2.00
; Total bytes of code 136, prolog size 20, PerfScore 48.10, instruction count 34, allocated bytes for code 136 (MethodHash=5b1221f0) for method System.Runtime.Intrinsics.Arm.AdvSimd:StoreSelectedScalar(ulong,System.Runtime.Intrinsics.Vector128`1[int],ubyte) (MinOpts)
; ============================================================

Interestingly, for some tests I got IndexOutOfRangeException earlier because the test was executing without an error but failing in the validation stage where it was accessing the out of range index. Only the first test was failing with an illegal instruction probably because of the code layout. Invalid index tried to jump to location that did not contain a valid index. For the further tests, the jump target at invalid index contained a valid instruction so it did not throw any exception during the execution.

@kunalspathak

Copy link
Copy Markdown
Contributor

Seems the indices of few test cases needs adjustment for them to not throw Exception.

@SwapnilGaikwad

SwapnilGaikwad commented Nov 2, 2023

Copy link
Copy Markdown
ContributorAuthor

Seems the indices of few test cases needs adjustment for them to not throw Exception.

Had to move the range check after recomputing the simdSize 🤦 . Now the current failures seems while sending the test data to helix system.

Comment threadsrc/coreclr/jit/hwintrinsicarm64.cpp Outdated
@SwapnilGaikwad

Copy link
Copy Markdown
ContributorAuthor

can you double check?

Sure! It's tricky to debug, and it isn't obvious why compilation of System.Runtime.Serialization.SerializationGuard would fail. I'll try rebasing/merging main, if the error persists then can debug further.

@kunalspathak

Copy link
Copy Markdown
Contributor

can you double check?

Sure! It's tricky to debug, and it isn't obvious why compilation of System.Runtime.Serialization.SerializationGuard would fail. I'll try rebasing/merging main, if the error persists then can debug further.

From what I remember, these tests were passing earlier and failing with the recent commit and are in arm64, so most likly related. I could be wrong.

@SwapnilGaikwad

Copy link
Copy Markdown
ContributorAuthor

can you double check?

Sure! It's tricky to debug, and it isn't obvious why compilation of System.Runtime.Serialization.SerializationGuard would fail. I'll try rebasing/merging main, if the error persists then can debug further.

From what I remember, these tests were passing earlier and failing with the recent commit and are in arm64, so most likly related. I could be wrong.

You're right, it seems to be related to the arg check. Not sure how to debug it though. I'll try to see if I can reproduce the failure. If that doesn't progress, should I put the explicit check as before?

@kunalspathak

kunalspathak commented Nov 6, 2023

Copy link
Copy Markdown
Contributor

If that doesn't progress, should I put the explicit check as before?

I would say just inspect the code changes and see if the code path for existing SelectedScalar with single vector is unchanged. That should fix the problem.

@kunalspathak

Copy link
Copy Markdown
Contributor

@SwapnilGaikwad - can you resolve the merge conflicts?

@fanyang-monofanyang-mono left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The change to Mono codebase looks good to me.

Change-Id: I81d386adbbcc195b777f436329f24438b0cca10c
@kunalspathak

Copy link
Copy Markdown
Contributor

The change to Mono codebase looks good to me.

@fanyang-mono - was the change essentially to make sure that mono continue to ignore newer APIs whose 2nd parameter is tuple and only support the existing StoreSelectedScalar API?

@fanyang-mono

fanyang-mono commented Nov 16, 2023

Copy link
Copy Markdown
Member

The change to Mono codebase looks good to me.

@fanyang-mono - was the change essentially to make sure that mono continue to ignore newer APIs whose 2nd parameter is tuple and only support the existing StoreSelectedScalar API?

Unfortunately, yes, Mono is not super friendly with handling API with 4 and more input arguments. We need to add additional code to handle those cases, rather than automatically handled by the machinery like Vector64/128. There is an issue to track Mono side of the work related to these new set of API's.

@kunalspathak
kunalspathak merged commit 2e912a3 into dotnet:mainNov 16, 2023
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Dec 17, 2023
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 SuperPMIcommunity-contributionIndicates that the PR has been added by a community membernew-api-needs-documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@SwapnilGaikwad@kunalspathak@fanyang-mono
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Implement StoreSelectedScalar for Arm64 - #93223

Merged
kunalspathak merged 24 commits into
dotnet:mainfrom
SwapnilGaikwad:github-st2-indexed
Nov 16, 2023
Merged

Implement StoreSelectedScalar for Arm64#93223
kunalspathak merged 24 commits into
dotnet:mainfrom
SwapnilGaikwad:github-st2-indexed

Conversation

@SwapnilGaikwad

@SwapnilGaikwadSwapnilGaikwad commented Oct 9, 2023

Copy link
Copy Markdown
Contributor

Contribute towards #84510.

// AdvSimd// ST2 (single structure)publicstaticunsafevoidStoreSelectedScalar64x2(byte*address,(Vector64<byte>Value1,Vector64<byte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(sbyte*address,(Vector64<sbyte>Value1,Vector64<sbyte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(short*address,(Vector64<short>Value1,Vector64<short>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(ushort*address,(Vector64<ushort>Value1,Vector64<ushort>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(int*address,(Vector64<int>Value1,Vector64<int>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(uint*address,(Vector64<uint>Value1,Vector64<uint>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(float*address,(Vector64<float>Value1,Vector64<float>Value2)value,byteindex);// ST3 (single structure)publicstaticunsafevoidStoreSelectedScalar64x3(byte*address,(Vector64<byte>Value1,Vector64<byte>Value2,Vector64<byte>Value3)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x3(sbyte*address,(Vector64<sbyte>Value1,Vector64<sbyte>Value2,Vector64<sbyte>Value3)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x3(short*address,(Vector64<short>Value1,Vector64<short>Value2,Vector64<short>Value3)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x3(ushort*address,(Vector64<ushort>Value1,Vector64<ushort>Value2,Vector64<ushort>Value3)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x3(int*address,(Vector64<int>Value1,Vector64<int>Value2,Vector64<int>Value3)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x3(uint*address,(Vector64<uint>Value1,Vector64<uint>Value2,Vector64<uint>Value3)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x3(float*address,(Vector64<float>Value1,Vector64<float>Value2,Vector64<float>Value3)value,byteindex);// ST4 (single structure)publicstaticunsafevoidStoreSelectedScalar64x4(byte*address,(Vector64<byte>Value1,Vector64<byte>Value2,Vector64<byte>Value3,Vector64<byte>Value4)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x4(sbyte*address,(Vector64<sbyte>Value1,Vector64<sbyte>Value2,Vector64<sbyte>Value3,Vector64<sbyte>Value4)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x4(short*address,(Vector64<short>Value1,Vector64<short>Value2,Vector64<short>Value3,Vector64<short>Value4)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x4(ushort*address,(Vector64<ushort>Value1,Vector64<ushort>Value2,Vector64<ushort>Value3,Vector64<ushort>Value4)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x4(int*address,(Vector64<int>Value1,Vector64<int>Value2,Vector64<int>Value3,Vector64<int>Value4)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x4(uint*address,(Vector64<uint>Value1,Vector64<uint>Value2,Vector64<uint>Value3,Vector64<uint>Value4)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x4(float*address,(Vector64<float>Value1,Vector64<float>Value2,Vector64<float>Value3,Vector64<float>Value4)value,byteindex);// AdvSimd.Arm64// ST2 (single structure)publicstaticunsafevoidStoreSelectedScalar128x2(byte*address,(Vector128<byte>Value1,Vector128<byte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(sbyte*address,(Vector128<sbyte>Value1,Vector128<sbyte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(short*address,(Vector128<short>Value1,Vector128<short>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(ushort*address,(Vector128<ushort>Value1,Vector128<ushort>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(int*address,(Vector128<int>Value1,Vector128<int>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(uint*address,(Vector128<uint>Value1,Vector128<uint>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(long*address,(Vector128<long>Value1,Vector128<long>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(ulong*address,(Vector128<ulong>Value1,Vector128<ulong>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(float*address,(Vector128<float>Value1,Vector128<float>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(double*address,(Vector128<double>Value1,Vector128<double>Value2)value,byteindex);// ST3 (single structure)publicstaticunsafevoidStoreSelectedScalar128x3(byte*address,(Vector128<byte>Value1,Vector128<byte>Value2,Vector128<byte>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(sbyte*address,(Vector128<sbyte>Value1,Vector128<sbyte>Value2,Vector128<sbyte>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(short*address,(Vector128<short>Value1,Vector128<short>Value2,Vector128<short>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(ushort*address,(Vector128<ushort>Value1,Vector128<ushort>Value2,Vector128<ushort>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(int*address,(Vector128<int>Value1,Vector128<int>Value2,Vector128<int>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(uint*address,(Vector128<uint>Value1,Vector128<uint>Value2,Vector128<uint>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(long*address,(Vector128<long>Value1,Vector128<long>Value2,Vector128<long>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(ulong*address,(Vector128<ulong>Value1,Vector128<ulong>Value2,Vector128<ulong>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(float*address,(Vector128<float>Value1,Vector128<float>Value2,Vector128<float>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(double*address,(Vector128<double>Value1,Vector128<double>Value2,Vector128<double>Value3),byteindex);// ST4 (single structure)publicstaticunsafevoidStoreSelectedScalar128x4(byte*address,(Vector128<byte>Value1,Vector128<byte>Value2,Vector128<byte>Value3,Vector128<byte>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(sbyte*address,(Vector128<sbyte>Value1,Vector128<sbyte>Value2,Vector128<sbyte>Value3,Vector128<sbyte>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(short*address,(Vector128<short>Value1,Vector128<short>Value2,Vector128<short>Value3,Vector128<short>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(ushort*address,(Vector128<ushort>Value1,Vector128<ushort>Value2,Vector128<ushort>Value3,Vector128<ushort>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(int*address,(Vector128<int>Value1,Vector128<int>Value2,Vector128<int>Value3,Vector128<int>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(uint*address,(Vector128<uint>Value1,Vector128<uint>Value2,Vector128<uint>Value3,Vector128<uint>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(long*address,(Vector128<long>Value1,Vector128<long>Value2,Vector128<long>Value3,Vector128<long>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(ulong*address,(Vector128<ulong>Value1,Vector128<ulong>Value2,Vector128<ulong>Value3,Vector128<ulong>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(float*address,(Vector128<float>Value1,Vector128<float>Value2,Vector128<float>Value3,Vector128<float>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(double*address,(Vector128<double>Value1,Vector128<double>Value2,Vector128<double>Value3,Vector128<double>Value4),byteindex);

@ghostghost added community-contribution Indicates that the PR has been added by a community member area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI new-api-needs-documentation labels Oct 9, 2023
@ghost

ghost commented Oct 9, 2023

Copy link
Copy Markdown

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

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

@ghost

ghost commented Oct 9, 2023

Copy link
Copy Markdown

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

Issue Details

Contribute towards #84510.

// AdvSimdpublicstaticunsafevoidStoreSelectedScalar64x2(byte*address,(Vector64<byte>Value1,Vector64<byte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(sbyte*address,(Vector64<sbyte>Value1,Vector64<sbyte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(short*address,(Vector64<short>Value1,Vector64<short>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(ushort*address,(Vector64<ushort>Value1,Vector64<ushort>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(int*address,(Vector64<int>Value1,Vector64<int>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(uint*address,(Vector64<uint>Value1,Vector64<uint>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(float*address,(Vector64<float>Value1,Vector64<float>Value2)value,byteindex);// AdvSimd.Arm64publicstaticunsafevoidStoreSelectedScalar128x2(byte*address,(Vector128<byte>Value1,Vector128<byte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(sbyte*address,(Vector128<sbyte>Value1,Vector128<sbyte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(short*address,(Vector128<short>Value1,Vector128<short>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(ushort*address,(Vector128<ushort>Value1,Vector128<ushort>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(int*address,(Vector128<int>Value1,Vector128<int>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(uint*address,(Vector128<uint>Value1,Vector128<uint>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(long*address,(Vector128<long>Value1,Vector128<long>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(ulong*address,(Vector128<ulong>Value1,Vector128<ulong>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(float*address,(Vector128<float>Value1,Vector128<float>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(double*address,(Vector128<double>Value1,Vector128<double>Value2)value,byteindex);
Author:SwapnilGaikwad
Assignees:-
Labels:

area-CodeGen-coreclr, new-api-needs-documentation, community-contribution

Milestone:-

@SwapnilGaikwad

Copy link
Copy Markdown
ContributorAuthor

This patch would emit the following assembly sequence

1. When the index is a constant value
AdvSimd.StoreSelectedScalar64x2((Int32*)_dataTable.outArrayPtr,(AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)),AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr))),1);
...
stp d8, d16, [fp, #0x10]	// [V18 tmp17], [V19 tmp18]
ldr q16, [fp, #0x10]	// [V04 tmp3]
ldr q17, [fp, #0x18]	// [V04 tmp3+0x08]
st2 {v16.s, v17.s}[1], [x20]
...
2. When index is not a constant
AdvSimd.StoreSelectedScalar64x2((Int32*)_dataTable.outArrayPtr,(AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)),AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr))),elemIndex);
...
mov x0, x21
movz x2, #0xC8A0 // code for System.Runtime.Intrinsics.Arm.AdvSimd:StoreSelectedScalar64x2(ulong,System.ValueTuple`2[System.Runtime.Intrinsics.Vector64`1[int],System.Runtime.Intrinsics.Vector64`1[int]],ubyte)
movk x2, #0x5DB8 LSL #16
movk x2, #0xFFFF LSL #32
ldr x2, [x2]
...
; Assembly listing for method System.Runtime.Intrinsics.Arm.AdvSimd:StoreSelectedScalar64x2(ulong,System.ValueTuple`2[System.Runtime.Intrinsics.Vector64`1[short],System.Runtime.Intrinsics.Vector64`1[short]],ubyte) (FullOpts)
G_M60890_IG01: ;; offset=0x0000
stp fp, lr, [sp, #-0x20]!
mov fp, sp
stp d0, d1, [fp, #0x10]	// [V01 arg1], [V01 arg1+0x08]
;; size=12 bbWeight=1 PerfScore 2.50
G_M60890_IG02: ;; offset=0x000C
ldr q16, [fp, #0x10]	// [V01 arg1]
ldr q17, [fp, #0x18]	// [V01 arg1+0x08]
uxtb w1, w1
adr x2, [G_M60890_IG03]
add x2, x2, x1, LSL #3
br x2
;; size=24 bbWeight=1 PerfScore 7.00
G_M60890_IG03: ;; offset=0x0024
st2 {v16.h, v17.h}[0], [x0]
b G_M60890_IG07
;; size=8 bbWeight=1 PerfScore 2.00
G_M60890_IG04: ;; offset=0x002C
st2 {v16.h, v17.h}[1], [x0]
b G_M60890_IG07
;; size=8 bbWeight=1 PerfScore 2.00
G_M60890_IG05: ;; offset=0x0034
st2 {v16.h, v17.h}[2], [x0]
b G_M60890_IG07
;; size=8 bbWeight=1 PerfScore 2.00
G_M60890_IG06: ;; offset=0x003C
st2 {v16.h, v17.h}[3], [x0]
;; size=4 bbWeight=1 PerfScore 1.00
G_M60890_IG07: ;; offset=0x0040
ldp fp, lr, [sp], #0x20
ret lr
;; size=8 bbWeight=1 PerfScore 2.00
3. When the index is variable and out of bounds The current test crashes with an error.
Illegal instruction (core dumped)

Not sure whether it's the desired behaviour. Also, I haven't considered the possibility of creating a ROP gadget with the sequence for Case 2 above. The sequence of instruction where value of an index can be used control the jump target.

@kunalspathak

Copy link
Copy Markdown
Contributor

As seen in #93197, the API names should be just StoreSelectedScalar because you can deduce the shape and tuple size from the parameters.

@kunalspathakkunalspathak left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I will double check about the immediate operand out of range scenario.

Comment threadsrc/coreclr/jit/emitarm64.cpp Outdated
Comment threadsrc/coreclr/jit/hwintrinsicarm64.cpp Outdated
Comment threadsrc/coreclr/jit/hwintrinsicarm64.cpp Outdated
Comment threadsrc/coreclr/jit/hwintrinsiclistarm64.h Outdated
Comment threadsrc/coreclr/jit/hwintrinsiclistarm64.h Outdated
@ghostghost added the needs-author-action An issue or pull request that requires more info or actions from the author. label Oct 9, 2023
@kunalspathak

Copy link
Copy Markdown
Contributor

I will double check about the immediate operand out of range scenario.

Alright, so if you follow #93197, the immOp is handled in it.

@kunalspathak

Copy link
Copy Markdown
Contributor
  1. When the index is variable and out of bounds

They should throw IndexOutOfBoundException

@ghostghost removed the needs-author-action An issue or pull request that requires more info or actions from the author. label Oct 16, 2023
@SwapnilGaikwadSwapnilGaikwad changed the title Implement StoreSelectedScalarNx2 for Arm64Implement StoreSelectedScalar for Arm64Oct 16, 2023
Comment threadsrc/coreclr/jit/hwintrinsic.cpp Outdated
Comment threadsrc/coreclr/jit/lsraarm64.cpp
Comment threadsrc/coreclr/jit/hwintrinsiclistarm64.h Outdated
Comment threadsrc/coreclr/jit/hwintrinsiccodegenarm64.cpp Outdated
Comment threadsrc/coreclr/jit/emitarm64.cpp
Comment threadsrc/coreclr/jit/hwintrinsic.cpp Outdated
@ghostghost added needs-author-action An issue or pull request that requires more info or actions from the author. and removed needs-author-action An issue or pull request that requires more info or actions from the author. labels Oct 16, 2023
@kunalspathak

Copy link
Copy Markdown
Contributor

RunBasicScenario_UnsafeRead segfaults with the following error

Interesting. What is the cause of it?

@SwapnilGaikwad

Copy link
Copy Markdown
ContributorAuthor

Now we get out of range exception for all the invalid scenarios (with constant or variable index) with all the test cases.

System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values.

I never got to ensure from the assembly that it throws InvalidIndexException. 🤔

This mystery is also resolved now. There was a check for array out of bounds missing. Now added it. Can be confirmed from the assembly for StoreSelectedScalar as well.

...
G_M56847_IG04:
ldr x0, [fp, #0x38]	// [V00 arg0]
ldr q16, [fp, #0x20]	// [V01 arg1]
ldr w1, [fp, #0x1C]	// [V02 arg2]
uxtb w1, w1
cmp w1, #4
blo G_M56847_IG05
bl CORINFO_HELP_THROW_ARGUMENTOUTOFRANGEEXCEPTION
...
Full assembly
; Assembly listing for method System.Runtime.Intrinsics.Arm.AdvSimd:StoreSelectedScalar(ulong,System.Runtime.Intrinsics.Vector128`1[int],ubyte) (MinOpts)
; Emitting BLENDED_CODE for generic ARM64 - Unix
; MinOpts code
; debuggable code
; fp based frame
; fully interruptible
; No PGO data
; Final local variable assignments
;
; V00 arg0 [V00 ] ( 1, 1 ) long -> [fp+0x38] do-not-enreg[]
; V01 arg1 [V01 ] ( 1, 1 ) simd16 -> [fp+0x20] HFA(simd16) do-not-enreg[S] <System.Runtime.Intrinsics.Vector128`1[int]>
; V02 arg2 [V02 ] ( 1, 1 ) ubyte -> [fp+0x1C] do-not-enreg[]
;# V03 OutArgs [V03 ] ( 1, 1 ) struct ( 0) [sp+0x00] do-not-enreg[XS] addr-exposed "OutgoingArgSpace"
;
; Lcl frame size = 48
G_M56847_IG01: ;; offset=0x0000
stp fp, lr, [sp, #-0x40]!
mov fp, sp
str x0, [fp, #0x38]	// [V00 arg0]
str w1, [fp, #0x1C]	// [V02 arg2]
str q0, [fp, #0x20]	// [V01 arg1]
;; size=20 bbWeight=1 PerfScore 4.50
G_M56847_IG02: ;; offset=0x0014
movz x0, #0x45A8
movk x0, #0x4004 LSL #16
movk x0, #0xFFFF LSL #32
ldr w0, [x0]
cbz w0, G_M56847_IG04
;; size=20 bbWeight=1 PerfScore 5.50
G_M56847_IG03: ;; offset=0x0028
bl CORINFO_HELP_DBG_IS_JUST_MY_CODE
;; size=4 bbWeight=0.50 PerfScore 0.50
G_M56847_IG04: ;; offset=0x002C
ldr x0, [fp, #0x38]	// [V00 arg0]
ldr q16, [fp, #0x20]	// [V01 arg1]
ldr w1, [fp, #0x1C]	// [V02 arg2]
uxtb w1, w1
cmp w1, #4
blo G_M56847_IG05
bl CORINFO_HELP_THROW_ARGUMENTOUTOFRANGEEXCEPTION
;; size=28 bbWeight=1 PerfScore 9.00
G_M56847_IG05: ;; offset=0x0048
ldr w1, [fp, #0x1C]	// [V02 arg2]
uxtb w1, w1
adr x2, [G_M56847_IG06]
add x2, x2, x1, LSL #3
br x2
;; size=20 bbWeight=1 PerfScore 5.00
G_M56847_IG06: ;; offset=0x005C
st1 {v16.s}[0], [x0]
b G_M56847_IG10
;; size=8 bbWeight=1 PerfScore 2.00
G_M56847_IG07: ;; offset=0x0064
st1 {v16.s}[1], [x0]
b G_M56847_IG10
;; size=8 bbWeight=1 PerfScore 2.00
G_M56847_IG08: ;; offset=0x006C
st1 {v16.s}[2], [x0]
b G_M56847_IG10
;; size=8 bbWeight=1 PerfScore 2.00
G_M56847_IG09: ;; offset=0x0074
st1 {v16.s}[3], [x0]
;; size=4 bbWeight=1 PerfScore 1.00
G_M56847_IG10: ;; offset=0x0078
nop
nop
;; size=8 bbWeight=1 PerfScore 1.00
G_M56847_IG11: ;; offset=0x0080
ldp fp, lr, [sp], #0x40
ret lr
;; size=8 bbWeight=1 PerfScore 2.00
; Total bytes of code 136, prolog size 20, PerfScore 48.10, instruction count 34, allocated bytes for code 136 (MethodHash=5b1221f0) for method System.Runtime.Intrinsics.Arm.AdvSimd:StoreSelectedScalar(ulong,System.Runtime.Intrinsics.Vector128`1[int],ubyte) (MinOpts)
; ============================================================

Interestingly, for some tests I got IndexOutOfRangeException earlier because the test was executing without an error but failing in the validation stage where it was accessing the out of range index. Only the first test was failing with an illegal instruction probably because of the code layout. Invalid index tried to jump to location that did not contain a valid index. For the further tests, the jump target at invalid index contained a valid instruction so it did not throw any exception during the execution.

@kunalspathak

Copy link
Copy Markdown
Contributor

Seems the indices of few test cases needs adjustment for them to not throw Exception.

@SwapnilGaikwad

SwapnilGaikwad commented Nov 2, 2023

Copy link
Copy Markdown
ContributorAuthor

Seems the indices of few test cases needs adjustment for them to not throw Exception.

Had to move the range check after recomputing the simdSize 🤦 . Now the current failures seems while sending the test data to helix system.

Comment threadsrc/coreclr/jit/hwintrinsicarm64.cpp Outdated
@SwapnilGaikwad

Copy link
Copy Markdown
ContributorAuthor

can you double check?

Sure! It's tricky to debug, and it isn't obvious why compilation of System.Runtime.Serialization.SerializationGuard would fail. I'll try rebasing/merging main, if the error persists then can debug further.

@kunalspathak

Copy link
Copy Markdown
Contributor

can you double check?

Sure! It's tricky to debug, and it isn't obvious why compilation of System.Runtime.Serialization.SerializationGuard would fail. I'll try rebasing/merging main, if the error persists then can debug further.

From what I remember, these tests were passing earlier and failing with the recent commit and are in arm64, so most likly related. I could be wrong.

@SwapnilGaikwad

Copy link
Copy Markdown
ContributorAuthor

can you double check?

Sure! It's tricky to debug, and it isn't obvious why compilation of System.Runtime.Serialization.SerializationGuard would fail. I'll try rebasing/merging main, if the error persists then can debug further.

From what I remember, these tests were passing earlier and failing with the recent commit and are in arm64, so most likly related. I could be wrong.

You're right, it seems to be related to the arg check. Not sure how to debug it though. I'll try to see if I can reproduce the failure. If that doesn't progress, should I put the explicit check as before?

@kunalspathak

kunalspathak commented Nov 6, 2023

Copy link
Copy Markdown
Contributor

If that doesn't progress, should I put the explicit check as before?

I would say just inspect the code changes and see if the code path for existing SelectedScalar with single vector is unchanged. That should fix the problem.

@kunalspathak

Copy link
Copy Markdown
Contributor

@SwapnilGaikwad - can you resolve the merge conflicts?

@fanyang-monofanyang-mono left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The change to Mono codebase looks good to me.

Change-Id: I81d386adbbcc195b777f436329f24438b0cca10c
@kunalspathak

Copy link
Copy Markdown
Contributor

The change to Mono codebase looks good to me.

@fanyang-mono - was the change essentially to make sure that mono continue to ignore newer APIs whose 2nd parameter is tuple and only support the existing StoreSelectedScalar API?

@fanyang-mono

fanyang-mono commented Nov 16, 2023

Copy link
Copy Markdown
Member

The change to Mono codebase looks good to me.

@fanyang-mono - was the change essentially to make sure that mono continue to ignore newer APIs whose 2nd parameter is tuple and only support the existing StoreSelectedScalar API?

Unfortunately, yes, Mono is not super friendly with handling API with 4 and more input arguments. We need to add additional code to handle those cases, rather than automatically handled by the machinery like Vector64/128. There is an issue to track Mono side of the work related to these new set of API's.

@kunalspathak
kunalspathak merged commit 2e912a3 into dotnet:mainNov 16, 2023
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Dec 17, 2023
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 SuperPMIcommunity-contributionIndicates that the PR has been added by a community membernew-api-needs-documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@SwapnilGaikwad@kunalspathak@fanyang-mono
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Implement StoreSelectedScalar for Arm64 - #93223

Merged
kunalspathak merged 24 commits into
dotnet:mainfrom
SwapnilGaikwad:github-st2-indexed
Nov 16, 2023
Merged

Implement StoreSelectedScalar for Arm64#93223
kunalspathak merged 24 commits into
dotnet:mainfrom
SwapnilGaikwad:github-st2-indexed

Conversation

@SwapnilGaikwad

@SwapnilGaikwadSwapnilGaikwad commented Oct 9, 2023

Copy link
Copy Markdown
Contributor

Contribute towards #84510.

// AdvSimd// ST2 (single structure)publicstaticunsafevoidStoreSelectedScalar64x2(byte*address,(Vector64<byte>Value1,Vector64<byte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(sbyte*address,(Vector64<sbyte>Value1,Vector64<sbyte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(short*address,(Vector64<short>Value1,Vector64<short>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(ushort*address,(Vector64<ushort>Value1,Vector64<ushort>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(int*address,(Vector64<int>Value1,Vector64<int>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(uint*address,(Vector64<uint>Value1,Vector64<uint>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(float*address,(Vector64<float>Value1,Vector64<float>Value2)value,byteindex);// ST3 (single structure)publicstaticunsafevoidStoreSelectedScalar64x3(byte*address,(Vector64<byte>Value1,Vector64<byte>Value2,Vector64<byte>Value3)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x3(sbyte*address,(Vector64<sbyte>Value1,Vector64<sbyte>Value2,Vector64<sbyte>Value3)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x3(short*address,(Vector64<short>Value1,Vector64<short>Value2,Vector64<short>Value3)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x3(ushort*address,(Vector64<ushort>Value1,Vector64<ushort>Value2,Vector64<ushort>Value3)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x3(int*address,(Vector64<int>Value1,Vector64<int>Value2,Vector64<int>Value3)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x3(uint*address,(Vector64<uint>Value1,Vector64<uint>Value2,Vector64<uint>Value3)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x3(float*address,(Vector64<float>Value1,Vector64<float>Value2,Vector64<float>Value3)value,byteindex);// ST4 (single structure)publicstaticunsafevoidStoreSelectedScalar64x4(byte*address,(Vector64<byte>Value1,Vector64<byte>Value2,Vector64<byte>Value3,Vector64<byte>Value4)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x4(sbyte*address,(Vector64<sbyte>Value1,Vector64<sbyte>Value2,Vector64<sbyte>Value3,Vector64<sbyte>Value4)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x4(short*address,(Vector64<short>Value1,Vector64<short>Value2,Vector64<short>Value3,Vector64<short>Value4)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x4(ushort*address,(Vector64<ushort>Value1,Vector64<ushort>Value2,Vector64<ushort>Value3,Vector64<ushort>Value4)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x4(int*address,(Vector64<int>Value1,Vector64<int>Value2,Vector64<int>Value3,Vector64<int>Value4)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x4(uint*address,(Vector64<uint>Value1,Vector64<uint>Value2,Vector64<uint>Value3,Vector64<uint>Value4)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x4(float*address,(Vector64<float>Value1,Vector64<float>Value2,Vector64<float>Value3,Vector64<float>Value4)value,byteindex);// AdvSimd.Arm64// ST2 (single structure)publicstaticunsafevoidStoreSelectedScalar128x2(byte*address,(Vector128<byte>Value1,Vector128<byte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(sbyte*address,(Vector128<sbyte>Value1,Vector128<sbyte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(short*address,(Vector128<short>Value1,Vector128<short>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(ushort*address,(Vector128<ushort>Value1,Vector128<ushort>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(int*address,(Vector128<int>Value1,Vector128<int>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(uint*address,(Vector128<uint>Value1,Vector128<uint>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(long*address,(Vector128<long>Value1,Vector128<long>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(ulong*address,(Vector128<ulong>Value1,Vector128<ulong>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(float*address,(Vector128<float>Value1,Vector128<float>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(double*address,(Vector128<double>Value1,Vector128<double>Value2)value,byteindex);// ST3 (single structure)publicstaticunsafevoidStoreSelectedScalar128x3(byte*address,(Vector128<byte>Value1,Vector128<byte>Value2,Vector128<byte>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(sbyte*address,(Vector128<sbyte>Value1,Vector128<sbyte>Value2,Vector128<sbyte>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(short*address,(Vector128<short>Value1,Vector128<short>Value2,Vector128<short>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(ushort*address,(Vector128<ushort>Value1,Vector128<ushort>Value2,Vector128<ushort>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(int*address,(Vector128<int>Value1,Vector128<int>Value2,Vector128<int>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(uint*address,(Vector128<uint>Value1,Vector128<uint>Value2,Vector128<uint>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(long*address,(Vector128<long>Value1,Vector128<long>Value2,Vector128<long>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(ulong*address,(Vector128<ulong>Value1,Vector128<ulong>Value2,Vector128<ulong>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(float*address,(Vector128<float>Value1,Vector128<float>Value2,Vector128<float>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(double*address,(Vector128<double>Value1,Vector128<double>Value2,Vector128<double>Value3),byteindex);// ST4 (single structure)publicstaticunsafevoidStoreSelectedScalar128x4(byte*address,(Vector128<byte>Value1,Vector128<byte>Value2,Vector128<byte>Value3,Vector128<byte>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(sbyte*address,(Vector128<sbyte>Value1,Vector128<sbyte>Value2,Vector128<sbyte>Value3,Vector128<sbyte>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(short*address,(Vector128<short>Value1,Vector128<short>Value2,Vector128<short>Value3,Vector128<short>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(ushort*address,(Vector128<ushort>Value1,Vector128<ushort>Value2,Vector128<ushort>Value3,Vector128<ushort>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(int*address,(Vector128<int>Value1,Vector128<int>Value2,Vector128<int>Value3,Vector128<int>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(uint*address,(Vector128<uint>Value1,Vector128<uint>Value2,Vector128<uint>Value3,Vector128<uint>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(long*address,(Vector128<long>Value1,Vector128<long>Value2,Vector128<long>Value3,Vector128<long>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(ulong*address,(Vector128<ulong>Value1,Vector128<ulong>Value2,Vector128<ulong>Value3,Vector128<ulong>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(float*address,(Vector128<float>Value1,Vector128<float>Value2,Vector128<float>Value3,Vector128<float>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(double*address,(Vector128<double>Value1,Vector128<double>Value2,Vector128<double>Value3,Vector128<double>Value4),byteindex);

@ghostghost added community-contribution Indicates that the PR has been added by a community member area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI new-api-needs-documentation labels Oct 9, 2023
@ghost

ghost commented Oct 9, 2023

Copy link
Copy Markdown

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

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

@ghost

ghost commented Oct 9, 2023

Copy link
Copy Markdown

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

Issue Details

Contribute towards #84510.

// AdvSimdpublicstaticunsafevoidStoreSelectedScalar64x2(byte*address,(Vector64<byte>Value1,Vector64<byte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(sbyte*address,(Vector64<sbyte>Value1,Vector64<sbyte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(short*address,(Vector64<short>Value1,Vector64<short>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(ushort*address,(Vector64<ushort>Value1,Vector64<ushort>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(int*address,(Vector64<int>Value1,Vector64<int>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(uint*address,(Vector64<uint>Value1,Vector64<uint>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(float*address,(Vector64<float>Value1,Vector64<float>Value2)value,byteindex);// AdvSimd.Arm64publicstaticunsafevoidStoreSelectedScalar128x2(byte*address,(Vector128<byte>Value1,Vector128<byte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(sbyte*address,(Vector128<sbyte>Value1,Vector128<sbyte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(short*address,(Vector128<short>Value1,Vector128<short>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(ushort*address,(Vector128<ushort>Value1,Vector128<ushort>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(int*address,(Vector128<int>Value1,Vector128<int>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(uint*address,(Vector128<uint>Value1,Vector128<uint>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(long*address,(Vector128<long>Value1,Vector128<long>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(ulong*address,(Vector128<ulong>Value1,Vector128<ulong>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(float*address,(Vector128<float>Value1,Vector128<float>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(double*address,(Vector128<double>Value1,Vector128<double>Value2)value,byteindex);
Author:SwapnilGaikwad
Assignees:-
Labels:

area-CodeGen-coreclr, new-api-needs-documentation, community-contribution

Milestone:-

@SwapnilGaikwad

Copy link
Copy Markdown
ContributorAuthor

This patch would emit the following assembly sequence

1. When the index is a constant value
AdvSimd.StoreSelectedScalar64x2((Int32*)_dataTable.outArrayPtr,(AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)),AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr))),1);
...
stp d8, d16, [fp, #0x10]	// [V18 tmp17], [V19 tmp18]
ldr q16, [fp, #0x10]	// [V04 tmp3]
ldr q17, [fp, #0x18]	// [V04 tmp3+0x08]
st2 {v16.s, v17.s}[1], [x20]
...
2. When index is not a constant
AdvSimd.StoreSelectedScalar64x2((Int32*)_dataTable.outArrayPtr,(AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)),AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr))),elemIndex);
...
mov x0, x21
movz x2, #0xC8A0 // code for System.Runtime.Intrinsics.Arm.AdvSimd:StoreSelectedScalar64x2(ulong,System.ValueTuple`2[System.Runtime.Intrinsics.Vector64`1[int],System.Runtime.Intrinsics.Vector64`1[int]],ubyte)
movk x2, #0x5DB8 LSL #16
movk x2, #0xFFFF LSL #32
ldr x2, [x2]
...
; Assembly listing for method System.Runtime.Intrinsics.Arm.AdvSimd:StoreSelectedScalar64x2(ulong,System.ValueTuple`2[System.Runtime.Intrinsics.Vector64`1[short],System.Runtime.Intrinsics.Vector64`1[short]],ubyte) (FullOpts)
G_M60890_IG01: ;; offset=0x0000
stp fp, lr, [sp, #-0x20]!
mov fp, sp
stp d0, d1, [fp, #0x10]	// [V01 arg1], [V01 arg1+0x08]
;; size=12 bbWeight=1 PerfScore 2.50
G_M60890_IG02: ;; offset=0x000C
ldr q16, [fp, #0x10]	// [V01 arg1]
ldr q17, [fp, #0x18]	// [V01 arg1+0x08]
uxtb w1, w1
adr x2, [G_M60890_IG03]
add x2, x2, x1, LSL #3
br x2
;; size=24 bbWeight=1 PerfScore 7.00
G_M60890_IG03: ;; offset=0x0024
st2 {v16.h, v17.h}[0], [x0]
b G_M60890_IG07
;; size=8 bbWeight=1 PerfScore 2.00
G_M60890_IG04: ;; offset=0x002C
st2 {v16.h, v17.h}[1], [x0]
b G_M60890_IG07
;; size=8 bbWeight=1 PerfScore 2.00
G_M60890_IG05: ;; offset=0x0034
st2 {v16.h, v17.h}[2], [x0]
b G_M60890_IG07
;; size=8 bbWeight=1 PerfScore 2.00
G_M60890_IG06: ;; offset=0x003C
st2 {v16.h, v17.h}[3], [x0]
;; size=4 bbWeight=1 PerfScore 1.00
G_M60890_IG07: ;; offset=0x0040
ldp fp, lr, [sp], #0x20
ret lr
;; size=8 bbWeight=1 PerfScore 2.00
3. When the index is variable and out of bounds The current test crashes with an error.
Illegal instruction (core dumped)

Not sure whether it's the desired behaviour. Also, I haven't considered the possibility of creating a ROP gadget with the sequence for Case 2 above. The sequence of instruction where value of an index can be used control the jump target.

@kunalspathak

Copy link
Copy Markdown
Contributor

As seen in #93197, the API names should be just StoreSelectedScalar because you can deduce the shape and tuple size from the parameters.

@kunalspathakkunalspathak left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I will double check about the immediate operand out of range scenario.

Comment threadsrc/coreclr/jit/emitarm64.cpp Outdated
Comment threadsrc/coreclr/jit/hwintrinsicarm64.cpp Outdated
Comment threadsrc/coreclr/jit/hwintrinsicarm64.cpp Outdated
Comment threadsrc/coreclr/jit/hwintrinsiclistarm64.h Outdated
Comment threadsrc/coreclr/jit/hwintrinsiclistarm64.h Outdated
@ghostghost added the needs-author-action An issue or pull request that requires more info or actions from the author. label Oct 9, 2023
@kunalspathak

Copy link
Copy Markdown
Contributor

I will double check about the immediate operand out of range scenario.

Alright, so if you follow #93197, the immOp is handled in it.

@kunalspathak

Copy link
Copy Markdown
Contributor
  1. When the index is variable and out of bounds

They should throw IndexOutOfBoundException

@ghostghost removed the needs-author-action An issue or pull request that requires more info or actions from the author. label Oct 16, 2023
@SwapnilGaikwadSwapnilGaikwad changed the title Implement StoreSelectedScalarNx2 for Arm64Implement StoreSelectedScalar for Arm64Oct 16, 2023
Comment threadsrc/coreclr/jit/hwintrinsic.cpp Outdated
Comment threadsrc/coreclr/jit/lsraarm64.cpp
Comment threadsrc/coreclr/jit/hwintrinsiclistarm64.h Outdated
Comment threadsrc/coreclr/jit/hwintrinsiccodegenarm64.cpp Outdated
Comment threadsrc/coreclr/jit/emitarm64.cpp
Comment threadsrc/coreclr/jit/hwintrinsic.cpp Outdated
@ghostghost added needs-author-action An issue or pull request that requires more info or actions from the author. and removed needs-author-action An issue or pull request that requires more info or actions from the author. labels Oct 16, 2023
@kunalspathak

Copy link
Copy Markdown
Contributor

RunBasicScenario_UnsafeRead segfaults with the following error

Interesting. What is the cause of it?

@SwapnilGaikwad

Copy link
Copy Markdown
ContributorAuthor

Now we get out of range exception for all the invalid scenarios (with constant or variable index) with all the test cases.

System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values.

I never got to ensure from the assembly that it throws InvalidIndexException. 🤔

This mystery is also resolved now. There was a check for array out of bounds missing. Now added it. Can be confirmed from the assembly for StoreSelectedScalar as well.

...
G_M56847_IG04:
ldr x0, [fp, #0x38]	// [V00 arg0]
ldr q16, [fp, #0x20]	// [V01 arg1]
ldr w1, [fp, #0x1C]	// [V02 arg2]
uxtb w1, w1
cmp w1, #4
blo G_M56847_IG05
bl CORINFO_HELP_THROW_ARGUMENTOUTOFRANGEEXCEPTION
...
Full assembly
; Assembly listing for method System.Runtime.Intrinsics.Arm.AdvSimd:StoreSelectedScalar(ulong,System.Runtime.Intrinsics.Vector128`1[int],ubyte) (MinOpts)
; Emitting BLENDED_CODE for generic ARM64 - Unix
; MinOpts code
; debuggable code
; fp based frame
; fully interruptible
; No PGO data
; Final local variable assignments
;
; V00 arg0 [V00 ] ( 1, 1 ) long -> [fp+0x38] do-not-enreg[]
; V01 arg1 [V01 ] ( 1, 1 ) simd16 -> [fp+0x20] HFA(simd16) do-not-enreg[S] <System.Runtime.Intrinsics.Vector128`1[int]>
; V02 arg2 [V02 ] ( 1, 1 ) ubyte -> [fp+0x1C] do-not-enreg[]
;# V03 OutArgs [V03 ] ( 1, 1 ) struct ( 0) [sp+0x00] do-not-enreg[XS] addr-exposed "OutgoingArgSpace"
;
; Lcl frame size = 48
G_M56847_IG01: ;; offset=0x0000
stp fp, lr, [sp, #-0x40]!
mov fp, sp
str x0, [fp, #0x38]	// [V00 arg0]
str w1, [fp, #0x1C]	// [V02 arg2]
str q0, [fp, #0x20]	// [V01 arg1]
;; size=20 bbWeight=1 PerfScore 4.50
G_M56847_IG02: ;; offset=0x0014
movz x0, #0x45A8
movk x0, #0x4004 LSL #16
movk x0, #0xFFFF LSL #32
ldr w0, [x0]
cbz w0, G_M56847_IG04
;; size=20 bbWeight=1 PerfScore 5.50
G_M56847_IG03: ;; offset=0x0028
bl CORINFO_HELP_DBG_IS_JUST_MY_CODE
;; size=4 bbWeight=0.50 PerfScore 0.50
G_M56847_IG04: ;; offset=0x002C
ldr x0, [fp, #0x38]	// [V00 arg0]
ldr q16, [fp, #0x20]	// [V01 arg1]
ldr w1, [fp, #0x1C]	// [V02 arg2]
uxtb w1, w1
cmp w1, #4
blo G_M56847_IG05
bl CORINFO_HELP_THROW_ARGUMENTOUTOFRANGEEXCEPTION
;; size=28 bbWeight=1 PerfScore 9.00
G_M56847_IG05: ;; offset=0x0048
ldr w1, [fp, #0x1C]	// [V02 arg2]
uxtb w1, w1
adr x2, [G_M56847_IG06]
add x2, x2, x1, LSL #3
br x2
;; size=20 bbWeight=1 PerfScore 5.00
G_M56847_IG06: ;; offset=0x005C
st1 {v16.s}[0], [x0]
b G_M56847_IG10
;; size=8 bbWeight=1 PerfScore 2.00
G_M56847_IG07: ;; offset=0x0064
st1 {v16.s}[1], [x0]
b G_M56847_IG10
;; size=8 bbWeight=1 PerfScore 2.00
G_M56847_IG08: ;; offset=0x006C
st1 {v16.s}[2], [x0]
b G_M56847_IG10
;; size=8 bbWeight=1 PerfScore 2.00
G_M56847_IG09: ;; offset=0x0074
st1 {v16.s}[3], [x0]
;; size=4 bbWeight=1 PerfScore 1.00
G_M56847_IG10: ;; offset=0x0078
nop
nop
;; size=8 bbWeight=1 PerfScore 1.00
G_M56847_IG11: ;; offset=0x0080
ldp fp, lr, [sp], #0x40
ret lr
;; size=8 bbWeight=1 PerfScore 2.00
; Total bytes of code 136, prolog size 20, PerfScore 48.10, instruction count 34, allocated bytes for code 136 (MethodHash=5b1221f0) for method System.Runtime.Intrinsics.Arm.AdvSimd:StoreSelectedScalar(ulong,System.Runtime.Intrinsics.Vector128`1[int],ubyte) (MinOpts)
; ============================================================

Interestingly, for some tests I got IndexOutOfRangeException earlier because the test was executing without an error but failing in the validation stage where it was accessing the out of range index. Only the first test was failing with an illegal instruction probably because of the code layout. Invalid index tried to jump to location that did not contain a valid index. For the further tests, the jump target at invalid index contained a valid instruction so it did not throw any exception during the execution.

@kunalspathak

Copy link
Copy Markdown
Contributor

Seems the indices of few test cases needs adjustment for them to not throw Exception.

@SwapnilGaikwad

SwapnilGaikwad commented Nov 2, 2023

Copy link
Copy Markdown
ContributorAuthor

Seems the indices of few test cases needs adjustment for them to not throw Exception.

Had to move the range check after recomputing the simdSize 🤦 . Now the current failures seems while sending the test data to helix system.

Comment threadsrc/coreclr/jit/hwintrinsicarm64.cpp Outdated
@SwapnilGaikwad

Copy link
Copy Markdown
ContributorAuthor

can you double check?

Sure! It's tricky to debug, and it isn't obvious why compilation of System.Runtime.Serialization.SerializationGuard would fail. I'll try rebasing/merging main, if the error persists then can debug further.

@kunalspathak

Copy link
Copy Markdown
Contributor

can you double check?

Sure! It's tricky to debug, and it isn't obvious why compilation of System.Runtime.Serialization.SerializationGuard would fail. I'll try rebasing/merging main, if the error persists then can debug further.

From what I remember, these tests were passing earlier and failing with the recent commit and are in arm64, so most likly related. I could be wrong.

@SwapnilGaikwad

Copy link
Copy Markdown
ContributorAuthor

can you double check?

Sure! It's tricky to debug, and it isn't obvious why compilation of System.Runtime.Serialization.SerializationGuard would fail. I'll try rebasing/merging main, if the error persists then can debug further.

From what I remember, these tests were passing earlier and failing with the recent commit and are in arm64, so most likly related. I could be wrong.

You're right, it seems to be related to the arg check. Not sure how to debug it though. I'll try to see if I can reproduce the failure. If that doesn't progress, should I put the explicit check as before?

@kunalspathak

kunalspathak commented Nov 6, 2023

Copy link
Copy Markdown
Contributor

If that doesn't progress, should I put the explicit check as before?

I would say just inspect the code changes and see if the code path for existing SelectedScalar with single vector is unchanged. That should fix the problem.

@kunalspathak

Copy link
Copy Markdown
Contributor

@SwapnilGaikwad - can you resolve the merge conflicts?

@fanyang-monofanyang-mono left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The change to Mono codebase looks good to me.

Change-Id: I81d386adbbcc195b777f436329f24438b0cca10c
@kunalspathak

Copy link
Copy Markdown
Contributor

The change to Mono codebase looks good to me.

@fanyang-mono - was the change essentially to make sure that mono continue to ignore newer APIs whose 2nd parameter is tuple and only support the existing StoreSelectedScalar API?

@fanyang-mono

fanyang-mono commented Nov 16, 2023

Copy link
Copy Markdown
Member

The change to Mono codebase looks good to me.

@fanyang-mono - was the change essentially to make sure that mono continue to ignore newer APIs whose 2nd parameter is tuple and only support the existing StoreSelectedScalar API?

Unfortunately, yes, Mono is not super friendly with handling API with 4 and more input arguments. We need to add additional code to handle those cases, rather than automatically handled by the machinery like Vector64/128. There is an issue to track Mono side of the work related to these new set of API's.

@kunalspathak
kunalspathak merged commit 2e912a3 into dotnet:mainNov 16, 2023
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Dec 17, 2023
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 SuperPMIcommunity-contributionIndicates that the PR has been added by a community membernew-api-needs-documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

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

Implement StoreSelectedScalar for Arm64 - #93223

Merged
kunalspathak merged 24 commits into
dotnet:mainfrom
SwapnilGaikwad:github-st2-indexed
Nov 16, 2023
Merged

Implement StoreSelectedScalar for Arm64#93223
kunalspathak merged 24 commits into
dotnet:mainfrom
SwapnilGaikwad:github-st2-indexed

Conversation

@SwapnilGaikwad

@SwapnilGaikwadSwapnilGaikwad commented Oct 9, 2023

Copy link
Copy Markdown
Contributor

Contribute towards #84510.

// AdvSimd// ST2 (single structure)publicstaticunsafevoidStoreSelectedScalar64x2(byte*address,(Vector64<byte>Value1,Vector64<byte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(sbyte*address,(Vector64<sbyte>Value1,Vector64<sbyte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(short*address,(Vector64<short>Value1,Vector64<short>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(ushort*address,(Vector64<ushort>Value1,Vector64<ushort>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(int*address,(Vector64<int>Value1,Vector64<int>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(uint*address,(Vector64<uint>Value1,Vector64<uint>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(float*address,(Vector64<float>Value1,Vector64<float>Value2)value,byteindex);// ST3 (single structure)publicstaticunsafevoidStoreSelectedScalar64x3(byte*address,(Vector64<byte>Value1,Vector64<byte>Value2,Vector64<byte>Value3)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x3(sbyte*address,(Vector64<sbyte>Value1,Vector64<sbyte>Value2,Vector64<sbyte>Value3)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x3(short*address,(Vector64<short>Value1,Vector64<short>Value2,Vector64<short>Value3)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x3(ushort*address,(Vector64<ushort>Value1,Vector64<ushort>Value2,Vector64<ushort>Value3)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x3(int*address,(Vector64<int>Value1,Vector64<int>Value2,Vector64<int>Value3)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x3(uint*address,(Vector64<uint>Value1,Vector64<uint>Value2,Vector64<uint>Value3)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x3(float*address,(Vector64<float>Value1,Vector64<float>Value2,Vector64<float>Value3)value,byteindex);// ST4 (single structure)publicstaticunsafevoidStoreSelectedScalar64x4(byte*address,(Vector64<byte>Value1,Vector64<byte>Value2,Vector64<byte>Value3,Vector64<byte>Value4)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x4(sbyte*address,(Vector64<sbyte>Value1,Vector64<sbyte>Value2,Vector64<sbyte>Value3,Vector64<sbyte>Value4)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x4(short*address,(Vector64<short>Value1,Vector64<short>Value2,Vector64<short>Value3,Vector64<short>Value4)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x4(ushort*address,(Vector64<ushort>Value1,Vector64<ushort>Value2,Vector64<ushort>Value3,Vector64<ushort>Value4)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x4(int*address,(Vector64<int>Value1,Vector64<int>Value2,Vector64<int>Value3,Vector64<int>Value4)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x4(uint*address,(Vector64<uint>Value1,Vector64<uint>Value2,Vector64<uint>Value3,Vector64<uint>Value4)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x4(float*address,(Vector64<float>Value1,Vector64<float>Value2,Vector64<float>Value3,Vector64<float>Value4)value,byteindex);// AdvSimd.Arm64// ST2 (single structure)publicstaticunsafevoidStoreSelectedScalar128x2(byte*address,(Vector128<byte>Value1,Vector128<byte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(sbyte*address,(Vector128<sbyte>Value1,Vector128<sbyte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(short*address,(Vector128<short>Value1,Vector128<short>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(ushort*address,(Vector128<ushort>Value1,Vector128<ushort>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(int*address,(Vector128<int>Value1,Vector128<int>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(uint*address,(Vector128<uint>Value1,Vector128<uint>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(long*address,(Vector128<long>Value1,Vector128<long>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(ulong*address,(Vector128<ulong>Value1,Vector128<ulong>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(float*address,(Vector128<float>Value1,Vector128<float>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(double*address,(Vector128<double>Value1,Vector128<double>Value2)value,byteindex);// ST3 (single structure)publicstaticunsafevoidStoreSelectedScalar128x3(byte*address,(Vector128<byte>Value1,Vector128<byte>Value2,Vector128<byte>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(sbyte*address,(Vector128<sbyte>Value1,Vector128<sbyte>Value2,Vector128<sbyte>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(short*address,(Vector128<short>Value1,Vector128<short>Value2,Vector128<short>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(ushort*address,(Vector128<ushort>Value1,Vector128<ushort>Value2,Vector128<ushort>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(int*address,(Vector128<int>Value1,Vector128<int>Value2,Vector128<int>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(uint*address,(Vector128<uint>Value1,Vector128<uint>Value2,Vector128<uint>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(long*address,(Vector128<long>Value1,Vector128<long>Value2,Vector128<long>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(ulong*address,(Vector128<ulong>Value1,Vector128<ulong>Value2,Vector128<ulong>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(float*address,(Vector128<float>Value1,Vector128<float>Value2,Vector128<float>Value3),byteindex);publicstaticunsafevoidStoreSelectedScalar128x3(double*address,(Vector128<double>Value1,Vector128<double>Value2,Vector128<double>Value3),byteindex);// ST4 (single structure)publicstaticunsafevoidStoreSelectedScalar128x4(byte*address,(Vector128<byte>Value1,Vector128<byte>Value2,Vector128<byte>Value3,Vector128<byte>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(sbyte*address,(Vector128<sbyte>Value1,Vector128<sbyte>Value2,Vector128<sbyte>Value3,Vector128<sbyte>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(short*address,(Vector128<short>Value1,Vector128<short>Value2,Vector128<short>Value3,Vector128<short>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(ushort*address,(Vector128<ushort>Value1,Vector128<ushort>Value2,Vector128<ushort>Value3,Vector128<ushort>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(int*address,(Vector128<int>Value1,Vector128<int>Value2,Vector128<int>Value3,Vector128<int>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(uint*address,(Vector128<uint>Value1,Vector128<uint>Value2,Vector128<uint>Value3,Vector128<uint>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(long*address,(Vector128<long>Value1,Vector128<long>Value2,Vector128<long>Value3,Vector128<long>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(ulong*address,(Vector128<ulong>Value1,Vector128<ulong>Value2,Vector128<ulong>Value3,Vector128<ulong>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(float*address,(Vector128<float>Value1,Vector128<float>Value2,Vector128<float>Value3,Vector128<float>Value4),byteindex);publicstaticunsafevoidStoreSelectedScalar128x4(double*address,(Vector128<double>Value1,Vector128<double>Value2,Vector128<double>Value3,Vector128<double>Value4),byteindex);

@ghostghost added community-contribution Indicates that the PR has been added by a community member area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI new-api-needs-documentation labels Oct 9, 2023
@ghost

ghost commented Oct 9, 2023

Copy link
Copy Markdown

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

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

@ghost

ghost commented Oct 9, 2023

Copy link
Copy Markdown

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

Issue Details

Contribute towards #84510.

// AdvSimdpublicstaticunsafevoidStoreSelectedScalar64x2(byte*address,(Vector64<byte>Value1,Vector64<byte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(sbyte*address,(Vector64<sbyte>Value1,Vector64<sbyte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(short*address,(Vector64<short>Value1,Vector64<short>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(ushort*address,(Vector64<ushort>Value1,Vector64<ushort>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(int*address,(Vector64<int>Value1,Vector64<int>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(uint*address,(Vector64<uint>Value1,Vector64<uint>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar64x2(float*address,(Vector64<float>Value1,Vector64<float>Value2)value,byteindex);// AdvSimd.Arm64publicstaticunsafevoidStoreSelectedScalar128x2(byte*address,(Vector128<byte>Value1,Vector128<byte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(sbyte*address,(Vector128<sbyte>Value1,Vector128<sbyte>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(short*address,(Vector128<short>Value1,Vector128<short>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(ushort*address,(Vector128<ushort>Value1,Vector128<ushort>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(int*address,(Vector128<int>Value1,Vector128<int>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(uint*address,(Vector128<uint>Value1,Vector128<uint>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(long*address,(Vector128<long>Value1,Vector128<long>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(ulong*address,(Vector128<ulong>Value1,Vector128<ulong>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(float*address,(Vector128<float>Value1,Vector128<float>Value2)value,byteindex);publicstaticunsafevoidStoreSelectedScalar128x2(double*address,(Vector128<double>Value1,Vector128<double>Value2)value,byteindex);
Author:SwapnilGaikwad
Assignees:-
Labels:

area-CodeGen-coreclr, new-api-needs-documentation, community-contribution

Milestone:-

@SwapnilGaikwad

Copy link
Copy Markdown
ContributorAuthor

This patch would emit the following assembly sequence

1. When the index is a constant value
AdvSimd.StoreSelectedScalar64x2((Int32*)_dataTable.outArrayPtr,(AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)),AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr))),1);
...
stp d8, d16, [fp, #0x10]	// [V18 tmp17], [V19 tmp18]
ldr q16, [fp, #0x10]	// [V04 tmp3]
ldr q17, [fp, #0x18]	// [V04 tmp3+0x08]
st2 {v16.s, v17.s}[1], [x20]
...
2. When index is not a constant
AdvSimd.StoreSelectedScalar64x2((Int32*)_dataTable.outArrayPtr,(AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)),AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr))),elemIndex);
...
mov x0, x21
movz x2, #0xC8A0 // code for System.Runtime.Intrinsics.Arm.AdvSimd:StoreSelectedScalar64x2(ulong,System.ValueTuple`2[System.Runtime.Intrinsics.Vector64`1[int],System.Runtime.Intrinsics.Vector64`1[int]],ubyte)
movk x2, #0x5DB8 LSL #16
movk x2, #0xFFFF LSL #32
ldr x2, [x2]
...
; Assembly listing for method System.Runtime.Intrinsics.Arm.AdvSimd:StoreSelectedScalar64x2(ulong,System.ValueTuple`2[System.Runtime.Intrinsics.Vector64`1[short],System.Runtime.Intrinsics.Vector64`1[short]],ubyte) (FullOpts)
G_M60890_IG01: ;; offset=0x0000
stp fp, lr, [sp, #-0x20]!
mov fp, sp
stp d0, d1, [fp, #0x10]	// [V01 arg1], [V01 arg1+0x08]
;; size=12 bbWeight=1 PerfScore 2.50
G_M60890_IG02: ;; offset=0x000C
ldr q16, [fp, #0x10]	// [V01 arg1]
ldr q17, [fp, #0x18]	// [V01 arg1+0x08]
uxtb w1, w1
adr x2, [G_M60890_IG03]
add x2, x2, x1, LSL #3
br x2
;; size=24 bbWeight=1 PerfScore 7.00
G_M60890_IG03: ;; offset=0x0024
st2 {v16.h, v17.h}[0], [x0]
b G_M60890_IG07
;; size=8 bbWeight=1 PerfScore 2.00
G_M60890_IG04: ;; offset=0x002C
st2 {v16.h, v17.h}[1], [x0]
b G_M60890_IG07
;; size=8 bbWeight=1 PerfScore 2.00
G_M60890_IG05: ;; offset=0x0034
st2 {v16.h, v17.h}[2], [x0]
b G_M60890_IG07
;; size=8 bbWeight=1 PerfScore 2.00
G_M60890_IG06: ;; offset=0x003C
st2 {v16.h, v17.h}[3], [x0]
;; size=4 bbWeight=1 PerfScore 1.00
G_M60890_IG07: ;; offset=0x0040
ldp fp, lr, [sp], #0x20
ret lr
;; size=8 bbWeight=1 PerfScore 2.00
3. When the index is variable and out of bounds The current test crashes with an error.
Illegal instruction (core dumped)

Not sure whether it's the desired behaviour. Also, I haven't considered the possibility of creating a ROP gadget with the sequence for Case 2 above. The sequence of instruction where value of an index can be used control the jump target.

@kunalspathak

Copy link
Copy Markdown
Contributor

As seen in #93197, the API names should be just StoreSelectedScalar because you can deduce the shape and tuple size from the parameters.

@kunalspathakkunalspathak left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I will double check about the immediate operand out of range scenario.

Comment threadsrc/coreclr/jit/emitarm64.cpp Outdated
Comment threadsrc/coreclr/jit/hwintrinsicarm64.cpp Outdated
Comment threadsrc/coreclr/jit/hwintrinsicarm64.cpp Outdated
Comment threadsrc/coreclr/jit/hwintrinsiclistarm64.h Outdated
Comment threadsrc/coreclr/jit/hwintrinsiclistarm64.h Outdated
@ghostghost added the needs-author-action An issue or pull request that requires more info or actions from the author. label Oct 9, 2023
@kunalspathak

Copy link
Copy Markdown
Contributor

I will double check about the immediate operand out of range scenario.

Alright, so if you follow #93197, the immOp is handled in it.

@kunalspathak

Copy link
Copy Markdown
Contributor
  1. When the index is variable and out of bounds

They should throw IndexOutOfBoundException

@ghostghost removed the needs-author-action An issue or pull request that requires more info or actions from the author. label Oct 16, 2023
@SwapnilGaikwadSwapnilGaikwad changed the title Implement StoreSelectedScalarNx2 for Arm64Implement StoreSelectedScalar for Arm64Oct 16, 2023
Comment threadsrc/coreclr/jit/hwintrinsic.cpp Outdated
Comment threadsrc/coreclr/jit/lsraarm64.cpp
Comment threadsrc/coreclr/jit/hwintrinsiclistarm64.h Outdated
Comment threadsrc/coreclr/jit/hwintrinsiccodegenarm64.cpp Outdated
Comment threadsrc/coreclr/jit/emitarm64.cpp
Comment threadsrc/coreclr/jit/hwintrinsic.cpp Outdated
@ghostghost added needs-author-action An issue or pull request that requires more info or actions from the author. and removed needs-author-action An issue or pull request that requires more info or actions from the author. labels Oct 16, 2023
@kunalspathak

Copy link
Copy Markdown
Contributor

RunBasicScenario_UnsafeRead segfaults with the following error

Interesting. What is the cause of it?

@SwapnilGaikwad

Copy link
Copy Markdown
ContributorAuthor

Now we get out of range exception for all the invalid scenarios (with constant or variable index) with all the test cases.

System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values.

I never got to ensure from the assembly that it throws InvalidIndexException. 🤔

This mystery is also resolved now. There was a check for array out of bounds missing. Now added it. Can be confirmed from the assembly for StoreSelectedScalar as well.

...
G_M56847_IG04:
ldr x0, [fp, #0x38]	// [V00 arg0]
ldr q16, [fp, #0x20]	// [V01 arg1]
ldr w1, [fp, #0x1C]	// [V02 arg2]
uxtb w1, w1
cmp w1, #4
blo G_M56847_IG05
bl CORINFO_HELP_THROW_ARGUMENTOUTOFRANGEEXCEPTION
...
Full assembly
; Assembly listing for method System.Runtime.Intrinsics.Arm.AdvSimd:StoreSelectedScalar(ulong,System.Runtime.Intrinsics.Vector128`1[int],ubyte) (MinOpts)
; Emitting BLENDED_CODE for generic ARM64 - Unix
; MinOpts code
; debuggable code
; fp based frame
; fully interruptible
; No PGO data
; Final local variable assignments
;
; V00 arg0 [V00 ] ( 1, 1 ) long -> [fp+0x38] do-not-enreg[]
; V01 arg1 [V01 ] ( 1, 1 ) simd16 -> [fp+0x20] HFA(simd16) do-not-enreg[S] <System.Runtime.Intrinsics.Vector128`1[int]>
; V02 arg2 [V02 ] ( 1, 1 ) ubyte -> [fp+0x1C] do-not-enreg[]
;# V03 OutArgs [V03 ] ( 1, 1 ) struct ( 0) [sp+0x00] do-not-enreg[XS] addr-exposed "OutgoingArgSpace"
;
; Lcl frame size = 48
G_M56847_IG01: ;; offset=0x0000
stp fp, lr, [sp, #-0x40]!
mov fp, sp
str x0, [fp, #0x38]	// [V00 arg0]
str w1, [fp, #0x1C]	// [V02 arg2]
str q0, [fp, #0x20]	// [V01 arg1]
;; size=20 bbWeight=1 PerfScore 4.50
G_M56847_IG02: ;; offset=0x0014
movz x0, #0x45A8
movk x0, #0x4004 LSL #16
movk x0, #0xFFFF LSL #32
ldr w0, [x0]
cbz w0, G_M56847_IG04
;; size=20 bbWeight=1 PerfScore 5.50
G_M56847_IG03: ;; offset=0x0028
bl CORINFO_HELP_DBG_IS_JUST_MY_CODE
;; size=4 bbWeight=0.50 PerfScore 0.50
G_M56847_IG04: ;; offset=0x002C
ldr x0, [fp, #0x38]	// [V00 arg0]
ldr q16, [fp, #0x20]	// [V01 arg1]
ldr w1, [fp, #0x1C]	// [V02 arg2]
uxtb w1, w1
cmp w1, #4
blo G_M56847_IG05
bl CORINFO_HELP_THROW_ARGUMENTOUTOFRANGEEXCEPTION
;; size=28 bbWeight=1 PerfScore 9.00
G_M56847_IG05: ;; offset=0x0048
ldr w1, [fp, #0x1C]	// [V02 arg2]
uxtb w1, w1
adr x2, [G_M56847_IG06]
add x2, x2, x1, LSL #3
br x2
;; size=20 bbWeight=1 PerfScore 5.00
G_M56847_IG06: ;; offset=0x005C
st1 {v16.s}[0], [x0]
b G_M56847_IG10
;; size=8 bbWeight=1 PerfScore 2.00
G_M56847_IG07: ;; offset=0x0064
st1 {v16.s}[1], [x0]
b G_M56847_IG10
;; size=8 bbWeight=1 PerfScore 2.00
G_M56847_IG08: ;; offset=0x006C
st1 {v16.s}[2], [x0]
b G_M56847_IG10
;; size=8 bbWeight=1 PerfScore 2.00
G_M56847_IG09: ;; offset=0x0074
st1 {v16.s}[3], [x0]
;; size=4 bbWeight=1 PerfScore 1.00
G_M56847_IG10: ;; offset=0x0078
nop
nop
;; size=8 bbWeight=1 PerfScore 1.00
G_M56847_IG11: ;; offset=0x0080
ldp fp, lr, [sp], #0x40
ret lr
;; size=8 bbWeight=1 PerfScore 2.00
; Total bytes of code 136, prolog size 20, PerfScore 48.10, instruction count 34, allocated bytes for code 136 (MethodHash=5b1221f0) for method System.Runtime.Intrinsics.Arm.AdvSimd:StoreSelectedScalar(ulong,System.Runtime.Intrinsics.Vector128`1[int],ubyte) (MinOpts)
; ============================================================

Interestingly, for some tests I got IndexOutOfRangeException earlier because the test was executing without an error but failing in the validation stage where it was accessing the out of range index. Only the first test was failing with an illegal instruction probably because of the code layout. Invalid index tried to jump to location that did not contain a valid index. For the further tests, the jump target at invalid index contained a valid instruction so it did not throw any exception during the execution.

@kunalspathak

Copy link
Copy Markdown
Contributor

Seems the indices of few test cases needs adjustment for them to not throw Exception.

@SwapnilGaikwad

SwapnilGaikwad commented Nov 2, 2023

Copy link
Copy Markdown
ContributorAuthor

Seems the indices of few test cases needs adjustment for them to not throw Exception.

Had to move the range check after recomputing the simdSize 🤦 . Now the current failures seems while sending the test data to helix system.

Comment threadsrc/coreclr/jit/hwintrinsicarm64.cpp Outdated
@SwapnilGaikwad

Copy link
Copy Markdown
ContributorAuthor

can you double check?

Sure! It's tricky to debug, and it isn't obvious why compilation of System.Runtime.Serialization.SerializationGuard would fail. I'll try rebasing/merging main, if the error persists then can debug further.

@kunalspathak

Copy link
Copy Markdown
Contributor

can you double check?

Sure! It's tricky to debug, and it isn't obvious why compilation of System.Runtime.Serialization.SerializationGuard would fail. I'll try rebasing/merging main, if the error persists then can debug further.

From what I remember, these tests were passing earlier and failing with the recent commit and are in arm64, so most likly related. I could be wrong.

@SwapnilGaikwad

Copy link
Copy Markdown
ContributorAuthor

can you double check?

Sure! It's tricky to debug, and it isn't obvious why compilation of System.Runtime.Serialization.SerializationGuard would fail. I'll try rebasing/merging main, if the error persists then can debug further.

From what I remember, these tests were passing earlier and failing with the recent commit and are in arm64, so most likly related. I could be wrong.

You're right, it seems to be related to the arg check. Not sure how to debug it though. I'll try to see if I can reproduce the failure. If that doesn't progress, should I put the explicit check as before?

@kunalspathak

kunalspathak commented Nov 6, 2023

Copy link
Copy Markdown
Contributor

If that doesn't progress, should I put the explicit check as before?

I would say just inspect the code changes and see if the code path for existing SelectedScalar with single vector is unchanged. That should fix the problem.

@kunalspathak

Copy link
Copy Markdown
Contributor

@SwapnilGaikwad - can you resolve the merge conflicts?

@fanyang-monofanyang-mono left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The change to Mono codebase looks good to me.

Change-Id: I81d386adbbcc195b777f436329f24438b0cca10c
@kunalspathak

Copy link
Copy Markdown
Contributor

The change to Mono codebase looks good to me.

@fanyang-mono - was the change essentially to make sure that mono continue to ignore newer APIs whose 2nd parameter is tuple and only support the existing StoreSelectedScalar API?

@fanyang-mono

fanyang-mono commented Nov 16, 2023

Copy link
Copy Markdown
Member

The change to Mono codebase looks good to me.

@fanyang-mono - was the change essentially to make sure that mono continue to ignore newer APIs whose 2nd parameter is tuple and only support the existing StoreSelectedScalar API?

Unfortunately, yes, Mono is not super friendly with handling API with 4 and more input arguments. We need to add additional code to handle those cases, rather than automatically handled by the machinery like Vector64/128. There is an issue to track Mono side of the work related to these new set of API's.

@kunalspathak
kunalspathak merged commit 2e912a3 into dotnet:mainNov 16, 2023
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Dec 17, 2023
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 SuperPMIcommunity-contributionIndicates that the PR has been added by a community membernew-api-needs-documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@SwapnilGaikwad@kunalspathak@fanyang-mono