ARM64-SVE: Add SVE registers to pal context - #103801

Merged
kunalspathak merged 29 commits into
dotnet:mainfrom
a74nh:sve_state_github
Jun 29, 2024
Merged

ARM64-SVE: Add SVE registers to pal context#103801
kunalspathak merged 29 commits into
dotnet:mainfrom
a74nh:sve_state_github

Conversation

@a74nh

@a74nha74nh commented Jun 21, 2024

Copy link
Copy Markdown
Contributor

Adds Linux support for SVE state on signals.

Testing:
I forced a sigill (by making one of the hwintrinsic API calls generate a bad instruction). I checked the SVE registers when the signal occurred. I stepped through and made sure the lpContext is correctly filled.

@ghostghost added the area-PAL-coreclr only for closed issues label Jun 21, 2024
@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Jun 21, 2024
Comment threadsrc/coreclr/pal/inc/pal.h Outdated
//
// Sve Registers
//
//TODO-SVE: How does this structure handle variable sized Z/P/FFR registers?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

AIUI, this should match the same structure in Windows. I don't have the any documentation, so I've made a guess at what the fields should be for SVE, and I expect that it's wrong
For convenience I've only used a vector length 128bits. I'd be surprised if windows supports a full 2048bit vector length without doing anything special.
(Offsets below marked with a ? I'll fix once the structure is correct)

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.

Windows in general don't store extended context parts in the CONTEXT data structure itself. There is a flag CONTEXT_XSTATE that indicates presence of extra data attached to the CONTEXT. There are APIs InitializeContext and InitializeContext2 that allows setting up a context for the extended state. It can be also used to get the size of memory needed for the extended context. The InitializeContext2 is a new one that allows to select only a subset of the extended state using the XStateCompactionMask argument.

We have done this differently for AVX512 for the sake of simplicity - we have included the extra registers in the CONTEXT structure itself. I think it would be better to move that to the way Windows handle that so that we don't waste time initializing and copying extra fields at places where we don't care about the extended state or when the current CPU doesn't support them. That would also allow to size the storage for the Z/P registers dynamically based on the current CPU.
Having said that though, for this PR, we can follow the suite and do the same thing we did for intel avx512 and migrate both to the better model later. Based on what @kunalspathak told me, starting with 128 bits of space for the registers should be sufficient for now.

I would add them to the very end of the CONTEXT after the debug registers so that the layout of the part that's common with Windows is the same.

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.

Yep, for the OS, extended context like SVE and AVX etc are stored in a variable-sized buffer separate from the CONTEXT. The CONTEXT_EX structure immediately follows the CONTEXT structure, and contains pointers to the variable-sized XSTATE buffer. On x64, the XSTATE buffer is in the exact format that is supported by the hardware via the XSAVE and XRSTOR instructions. On ARM64, there are no XSAVE/XRSTOR instructions, but the XSTATE buffer is laid out in a similar fashion to x64 (including Header->Mask, Header->CompationMask etc), to allow for max code sharing with x64.

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.

The OS kernel does support all SVE vector lengths, up to 2048-bit SVE, though there is the caveat that HyperV only supports 128-bit SVE. So, when running on hardware that supports SVE larger than 128-bits, if HyperV is enabled you'll only see 128-bit SVE, but if HyperV is off then you'll be able to take advantage of the full SVE width supported by the CPU. And to my understanding, there is likely hardware in the future that supports larger SVE lengths than 128-bit, though I don't know any specific on timelines.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks for the comments. Updated with the following:

  • Added context2.S changes
  • Removed store/restore of Z registers (as we only support 128bits for now, which fully overlap the V registers)
  • Added a XStateFeaturesMask to the Arm64 context so that we can tell whether to use SVE or not.

I'm currently unsure where else SVE state might need saving/restoring

@a74nh

Copy link
Copy Markdown
ContributorAuthor

Things I'm unsure about:

  • What the LPCONTEXT should look like
  • If there are extra areas in coreclr that need covering
    • I think AOT needs convering too. But SVE is no yet supported in AOT
    • Do the SVE registers need propagating anywhere else?
  • Is there a testsuite for this?

@a74nh
a74nh marked this pull request as ready for review June 21, 2024 13:22
@a74nh

Copy link
Copy Markdown
ContributorAuthor

Build failures on Windows, but I expected that as that all still needs doing. Marking as ready as I could do with comments, especially on the Windows side.

@dotnet/arm64-contrib @kunalspathak@tannergooding

@kunalspathakkunalspathak added the arm-sve Work related to arm64 SVE/SVE2 support label Jun 21, 2024
@kunalspathak

Copy link
Copy Markdown
Contributor

@JasonLinMS

Comment threadsrc/coreclr/debug/inc/dbgtargetcontext.h Outdated
Comment threadsrc/coreclr/pal/inc/pal.h Outdated
Comment threadsrc/coreclr/pal/src/arch/arm64/context2.S Outdated
}
}

if (sve)

@janvorlijanvorliJun 27, 2024

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.

Similar to x64, we should copy the state only if the contextFlags has the CONTEXT_XSTATE flag set. The passed in contextFlags list parts of the state that are valid that the caller is interested in.

It seems it would make sense to move this to the end of the function next to where we extract xstate for amd64 and put it under the same if ((contextFlags & CONTEXT_XSTATE) == CONTEXT_XSTATE).

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Similar to x64, we should copy the state only if the contextFlags has the CONTEXT_XSTATE flag set.

There is one remaining test failure I've just debugged to being due to this. Will fix it up.

sub x0, x0, CONTEXT_FLOAT_CONTROL_OFFSET + CONTEXT_NEON_OFFSET

LOCAL_LABEL(Done_CONTEXT_FLOATING_POINT):
ldr x1, [x0, CONTEXT_XSTATEFEATURESMASK_OFFSET]

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.

It should check the CONTEXT_XSTATE in CONTEXT_ContextFlags first and check the features mask only if the CONTEXT_XSTATE is set.

// since we potentially clobber x0 below, we'll bank it in x16
mov x16, x0

ldr w17, [x16, CONTEXT_XSTATEFEATURESMASK_OFFSET]

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.

It should check the CONTEXT_XSTATE in CONTEXT_ContextFlags first and check the features mask only if the CONTEXT_XSTATE is set.

#endif // XSTATE_SUPPORTED || (HOST_AMD64 && HAVE_MACH_EXCEPTIONS)

#if defined(HOST_64BIT) && defined(HOST_ARM64) && !defined(TARGET_FREEBSD) && !defined(TARGET_OSX)
#if !defined(SVE_MAGIC)

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.

Is this define not present when building in our CI?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Is this define not present when building in our CI?

Yes, they are missing in the CI. If I remove any of them the build falls over. I think this is when cross compiling. Eithe way, it must be an old Linux being used because these defines have been present in Linux since about 2017.

@janvorli

Copy link
Copy Markdown
Member

Besides the few comments, it looks good.

@a74nh

Copy link
Copy Markdown
ContributorAuthor

Fixed up so that XSTATE is set and checked as suggested.
Everything in run.sh passes and I can see state getting copied when debugging around signals.

This PR enables -DXSTATE_SUPPORTED on Arm64. Am I correct in thinking that on AMD64 Windows this flag is also used in certain scenarios to ensure the xstate data is block copied? If that is the case, then on Arm64 Windows this support still needs adding - probably by just enabling some AMD64 defines for ARM64. However, I've not go a windows setup and so don't want to blindly do anything here and recommend someone checks windows this after this PR is merged.

@a74nh

Copy link
Copy Markdown
ContributorAuthor

Running all priority 1 tests in checked on SVE Linux....

Time [secs] | Total | Passed | Failed | Skipped | Assembly Execution Summary
============================================================================
30.836 | 131 | 131 | 0 | 0 | JIT.Regression.Regression_4
13.873 | 345 | 342 | 0 | 3 | JIT.Regression.Regression_3
13.446 | 53 | 53 | 0 | 0 | CoreMangLib.CoreMangLib
11.249 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests900-999
13.538 | 76 | 76 | 0 | 0 | GC.API.XUnitWrapper.dll
1.225 | 3 | 3 | 0 | 0 | GC.Coverage.XUnitWrapper.dll
183.980 | 42 | 42 | 0 | 0 | GC.Features.XUnitWrapper.dll
3.100 | 6 | 6 | 0 | 0 | GC.LargeMemory.XUnitWrapper.dll
4.731 | 12 | 12 | 0 | 0 | GC.Regressions.XUnitWrapper.dll
22.314 | 481 | 481 | 0 | 0 | GC.Scenarios.XUnitWrapper.dll
0.039 | 1 | 1 | 0 | 0 | GC.Stress.XUnitWrapper.dll
0.534 | 1 | 1 | 0 | 0 | ilasm.PortablePdb.XUnitWrapper.dll
0.619 | 1 | 1 | 0 | 0 | ilasm.System.XUnitWrapper.dll
2.668 | 1 | 1 | 0 | 0 | ilverify.XUnitWrapper.dll
0.537 | 2 | 2 | 0 | 0 | profiler.assembly.XUnitWrapper.dll
1.236 | 2 | 2 | 0 | 0 | profiler.elt.XUnitWrapper.dll
0.793 | 3 | 3 | 0 | 0 | profiler.eventpipe.XUnitWrapper.dll
0.983 | 4 | 4 | 0 | 0 | profiler.gc.XUnitWrapper.dll
0.557 | 1 | 1 | 0 | 0 | profiler.handles.XUnitWrapper.dll
0.038 | 1 | 1 | 0 | 0 | profiler.multiple.XUnitWrapper.dll
0.037 | 1 | 1 | 0 | 0 | profiler.rejit.XUnitWrapper.dll
1.360 | 1 | 1 | 0 | 0 | profiler.transitions.XUnitWrapper.dll
4.133 | 5 | 5 | 0 | 0 | profiler.unittest.XUnitWrapper.dll
0.117 | 1 | 0 | 0 | 1 | JIT.jit64.jit64_2
5.451 | 116 | 116 | 0 | 0 | JIT.SIMD.JIT.SIMD
6.433 | 101 | 101 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests1400-1599
4.025 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests200-299
10.097 | 230 | 227 | 1 | 2 | JIT.Directed.Directed_3
19.526 | 214 | 214 | 0 | 0 | JIT.Directed.Directed_1
5.211 | 216 | 216 | 0 | 0 | JIT.Generics.JIT.Generics
8.080 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests1200-1299
12.593 | 16 | 16 | 0 | 0 | reflection.reflection
138.821 | 100 | 100 | 0 | 0 | JIT.Performance.JIT.performance
172.627 | 11 | 11 | 0 | 0 | JIT.JIT_others
2.365 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests0-99
1.128 | 2 | 1 | 0 | 1 | Exceptions.Exceptions
60.075 | 88 | 88 | 0 | 0 | baseservices.threading.threading_group2
2.885 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests500-599
158.641 | 322 | 321 | 0 | 1 | Loader.Loader
17.855 | 226 | 207 | 0 | 19 | Interop.Interop
5.244 | 437 | 433 | 0 | 4 | JIT.Regression.Regression_6
8.702 | 641 | 641 | 0 | 0 | JIT.CodeGenBringUpTests.JIT.CodeGenBringUpTests
6.596 | 16 | 16 | 0 | 0 | JIT.JIT_r
23.990 | 482 | 480 | 0 | 2 | JIT.Regression.Regression_1
8.302 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests700-799
0.522 | 3 | 3 | 0 | 0 | JIT.JIT_do
9.039 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests1100-1199
2.658 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests400-499
48.146 | 112 | 112 | 0 | 0 | JIT.jit64.jit64_1
84.672 | 1 | 1 | 0 | 0 | readytorun.coreroot_determinism.readytorun_coreroot_determinism
13.396 | 215 | 215 | 0 | 0 | Loader.classloader.generics.LoaderClassloaderGenerics
2.474 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests100-199
43.988 | 2551 | 2551 | 0 | 0 | JIT.HardwareIntrinsics.HardwareIntrinsics_General_ro
9.626 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests1300-1399
76.360 | 75 | 75 | 0 | 0 | Regressions.Regressions
5.244 | 211 | 210 | 0 | 1 | JIT.Methodical.Methodical_r2
5.458 | 85 | 85 | 0 | 0 | JIT.Methodical.Methodical_ro
9.593 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests800-899
75.522 | 20 | 18 | 0 | 2 | readytorun.readytorun
12.881 | 279 | 279 | 0 | 0 | JIT.Methodical.Methodical_r1
3.120 | 343 | 343 | 0 | 0 | JIT.jit64.jit64_4
1.532 | 47 | 47 | 0 | 0 | JIT.Regression.Regression_5
41.352 | 144 | 142 | 0 | 2 | baseservices.exceptions.baseservices-exceptions
9.289 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests1000-1099
18.946 | 67 | 67 | 0 | 0 | Loader.classloader.regressions.LoaderClassloaderRegressions
83.636 | 355 | 353 | 0 | 2 | JIT.opt.JIT.opt
5.979 | 85 | 85 | 0 | 0 | JIT.Methodical.Methodical_do
4.367 | 35 | 33 | 0 | 2 | tracing.tracing
37.561 | 485 | 484 | 0 | 1 | JIT.Regression.Regression_2
13.844 | 276 | 276 | 0 | 0 | JIT.Methodical.Methodical_d1
0.467 | 2 | 2 | 0 | 0 | JIT.JIT_d
92.261 | 143 | 139 | 0 | 4 | JIT.jit64.jit64_3
6.514 | 16 | 16 | 0 | 0 | JIT.JIT_ro
50.519 | 39 | 35 | 0 | 4 | baseservices.baseservices
7.336 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests600-699
5.981 | 208 | 207 | 0 | 1 | JIT.Methodical.Methodical_d2
35.809 | 231 | 226 | 0 | 5 | JIT.jit64.jit64_5
49.200 | 2584 | 2584 | 0 | 0 | JIT.HardwareIntrinsics.HardwareIntrinsics_General_r
1.555 | 55 | 54 | 0 | 1 | JIT.Methodical.Methodical_others
3.838 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests300-399
0.088 | 0 | 0 | 0 | 0 | managed.Managed
54.354 | 203 | 199 | 0 | 4 | JIT.Directed.Directed_2
2.741 | 405 | 405 | 0 | 0 | JIT.IL_Conformance.IL_Conformance
77.532 | 82 | 81 | 0 | 1 | baseservices.threading.threading_group1
----------------------------------------------------------------------------
1997.991 | 15149 | 15085 | 1 | 63 | (total)

That single failure I get on latest head, so I'm not worried about it.

Comment threadsrc/coreclr/pal/src/arch/arm64/context2.S
@jkotas

Copy link
Copy Markdown
Member

I see a lot of TODOs about SVE size being hardcoded to 128 bit.

What is going to be the experience when somebody runs .NET 9 binary on a machine with 256 bit SVE? It is important that it just works, without crashing, buffer overruns, etc.

@a74nh

Copy link
Copy Markdown
ContributorAuthor

I see a lot of TODOs about SVE size being hardcoded to 128 bit.

What is going to be the experience when somebody runs .NET 9 binary on a machine with 256 bit SVE? It is important that it just works, without crashing, buffer overruns, etc.

Running the entire testsuite on 256bit, all the tests pass with and without my latest fix. That's because there is no SVE state in the kernel, so that structure that comes back from the OS has no SVE state (sve.size is 16, it's just the header with no data).

Comment threadsrc/coreclr/pal/src/arch/arm64/asmconstants.h

@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.

Thanks @a74nh for your contribution. LGTM.

@kunalspathak

Copy link
Copy Markdown
Contributor

/ba-g failure is #103550

@kunalspathak
kunalspathak merged commit 9528c15 into dotnet:mainJun 29, 2024
akoeplinger added a commit to akoeplinger/runtime that referenced this pull request Jul 8, 2024
It got broken by dotnet#103801 due to a host vs. target arch typo.
This showed up in the VMR since we use arm64 macOS build agents there.
akoeplinger added a commit to akoeplinger/runtime that referenced this pull request Jul 8, 2024
It got uncovered by dotnet#103801.
This showed up in the VMR since we use arm64 macOS build agents there.
akoeplinger added a commit that referenced this pull request Jul 8, 2024
It got uncovered by #103801.
This showed up in the VMR since we use arm64 macOS build agents there.
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jul 29, 2024
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-PAL-coreclronly for closed issuesarm-sveWork related to arm64 SVE/SVE2 supportcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@a74nh@kunalspathak@janvorli@jkotas@JasonLinMS
, '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

ARM64-SVE: Add SVE registers to pal context - #103801

Merged
kunalspathak merged 29 commits into
dotnet:mainfrom
a74nh:sve_state_github
Jun 29, 2024
Merged

ARM64-SVE: Add SVE registers to pal context#103801
kunalspathak merged 29 commits into
dotnet:mainfrom
a74nh:sve_state_github

Conversation

@a74nh

@a74nha74nh commented Jun 21, 2024

Copy link
Copy Markdown
Contributor

Adds Linux support for SVE state on signals.

Testing:
I forced a sigill (by making one of the hwintrinsic API calls generate a bad instruction). I checked the SVE registers when the signal occurred. I stepped through and made sure the lpContext is correctly filled.

@ghostghost added the area-PAL-coreclr only for closed issues label Jun 21, 2024
@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Jun 21, 2024
Comment threadsrc/coreclr/pal/inc/pal.h Outdated
//
// Sve Registers
//
//TODO-SVE: How does this structure handle variable sized Z/P/FFR registers?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

AIUI, this should match the same structure in Windows. I don't have the any documentation, so I've made a guess at what the fields should be for SVE, and I expect that it's wrong
For convenience I've only used a vector length 128bits. I'd be surprised if windows supports a full 2048bit vector length without doing anything special.
(Offsets below marked with a ? I'll fix once the structure is correct)

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.

Windows in general don't store extended context parts in the CONTEXT data structure itself. There is a flag CONTEXT_XSTATE that indicates presence of extra data attached to the CONTEXT. There are APIs InitializeContext and InitializeContext2 that allows setting up a context for the extended state. It can be also used to get the size of memory needed for the extended context. The InitializeContext2 is a new one that allows to select only a subset of the extended state using the XStateCompactionMask argument.

We have done this differently for AVX512 for the sake of simplicity - we have included the extra registers in the CONTEXT structure itself. I think it would be better to move that to the way Windows handle that so that we don't waste time initializing and copying extra fields at places where we don't care about the extended state or when the current CPU doesn't support them. That would also allow to size the storage for the Z/P registers dynamically based on the current CPU.
Having said that though, for this PR, we can follow the suite and do the same thing we did for intel avx512 and migrate both to the better model later. Based on what @kunalspathak told me, starting with 128 bits of space for the registers should be sufficient for now.

I would add them to the very end of the CONTEXT after the debug registers so that the layout of the part that's common with Windows is the same.

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.

Yep, for the OS, extended context like SVE and AVX etc are stored in a variable-sized buffer separate from the CONTEXT. The CONTEXT_EX structure immediately follows the CONTEXT structure, and contains pointers to the variable-sized XSTATE buffer. On x64, the XSTATE buffer is in the exact format that is supported by the hardware via the XSAVE and XRSTOR instructions. On ARM64, there are no XSAVE/XRSTOR instructions, but the XSTATE buffer is laid out in a similar fashion to x64 (including Header->Mask, Header->CompationMask etc), to allow for max code sharing with x64.

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.

The OS kernel does support all SVE vector lengths, up to 2048-bit SVE, though there is the caveat that HyperV only supports 128-bit SVE. So, when running on hardware that supports SVE larger than 128-bits, if HyperV is enabled you'll only see 128-bit SVE, but if HyperV is off then you'll be able to take advantage of the full SVE width supported by the CPU. And to my understanding, there is likely hardware in the future that supports larger SVE lengths than 128-bit, though I don't know any specific on timelines.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks for the comments. Updated with the following:

  • Added context2.S changes
  • Removed store/restore of Z registers (as we only support 128bits for now, which fully overlap the V registers)
  • Added a XStateFeaturesMask to the Arm64 context so that we can tell whether to use SVE or not.

I'm currently unsure where else SVE state might need saving/restoring

@a74nh

Copy link
Copy Markdown
ContributorAuthor

Things I'm unsure about:

  • What the LPCONTEXT should look like
  • If there are extra areas in coreclr that need covering
    • I think AOT needs convering too. But SVE is no yet supported in AOT
    • Do the SVE registers need propagating anywhere else?
  • Is there a testsuite for this?

@a74nh
a74nh marked this pull request as ready for review June 21, 2024 13:22
@a74nh

Copy link
Copy Markdown
ContributorAuthor

Build failures on Windows, but I expected that as that all still needs doing. Marking as ready as I could do with comments, especially on the Windows side.

@dotnet/arm64-contrib @kunalspathak@tannergooding

@kunalspathakkunalspathak added the arm-sve Work related to arm64 SVE/SVE2 support label Jun 21, 2024
@kunalspathak

Copy link
Copy Markdown
Contributor

@JasonLinMS

Comment threadsrc/coreclr/debug/inc/dbgtargetcontext.h Outdated
Comment threadsrc/coreclr/pal/inc/pal.h Outdated
Comment threadsrc/coreclr/pal/src/arch/arm64/context2.S Outdated
}
}

if (sve)

@janvorlijanvorliJun 27, 2024

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.

Similar to x64, we should copy the state only if the contextFlags has the CONTEXT_XSTATE flag set. The passed in contextFlags list parts of the state that are valid that the caller is interested in.

It seems it would make sense to move this to the end of the function next to where we extract xstate for amd64 and put it under the same if ((contextFlags & CONTEXT_XSTATE) == CONTEXT_XSTATE).

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Similar to x64, we should copy the state only if the contextFlags has the CONTEXT_XSTATE flag set.

There is one remaining test failure I've just debugged to being due to this. Will fix it up.

sub x0, x0, CONTEXT_FLOAT_CONTROL_OFFSET + CONTEXT_NEON_OFFSET

LOCAL_LABEL(Done_CONTEXT_FLOATING_POINT):
ldr x1, [x0, CONTEXT_XSTATEFEATURESMASK_OFFSET]

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.

It should check the CONTEXT_XSTATE in CONTEXT_ContextFlags first and check the features mask only if the CONTEXT_XSTATE is set.

// since we potentially clobber x0 below, we'll bank it in x16
mov x16, x0

ldr w17, [x16, CONTEXT_XSTATEFEATURESMASK_OFFSET]

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.

It should check the CONTEXT_XSTATE in CONTEXT_ContextFlags first and check the features mask only if the CONTEXT_XSTATE is set.

#endif // XSTATE_SUPPORTED || (HOST_AMD64 && HAVE_MACH_EXCEPTIONS)

#if defined(HOST_64BIT) && defined(HOST_ARM64) && !defined(TARGET_FREEBSD) && !defined(TARGET_OSX)
#if !defined(SVE_MAGIC)

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.

Is this define not present when building in our CI?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Is this define not present when building in our CI?

Yes, they are missing in the CI. If I remove any of them the build falls over. I think this is when cross compiling. Eithe way, it must be an old Linux being used because these defines have been present in Linux since about 2017.

@janvorli

Copy link
Copy Markdown
Member

Besides the few comments, it looks good.

@a74nh

Copy link
Copy Markdown
ContributorAuthor

Fixed up so that XSTATE is set and checked as suggested.
Everything in run.sh passes and I can see state getting copied when debugging around signals.

This PR enables -DXSTATE_SUPPORTED on Arm64. Am I correct in thinking that on AMD64 Windows this flag is also used in certain scenarios to ensure the xstate data is block copied? If that is the case, then on Arm64 Windows this support still needs adding - probably by just enabling some AMD64 defines for ARM64. However, I've not go a windows setup and so don't want to blindly do anything here and recommend someone checks windows this after this PR is merged.

@a74nh

Copy link
Copy Markdown
ContributorAuthor

Running all priority 1 tests in checked on SVE Linux....

Time [secs] | Total | Passed | Failed | Skipped | Assembly Execution Summary
============================================================================
30.836 | 131 | 131 | 0 | 0 | JIT.Regression.Regression_4
13.873 | 345 | 342 | 0 | 3 | JIT.Regression.Regression_3
13.446 | 53 | 53 | 0 | 0 | CoreMangLib.CoreMangLib
11.249 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests900-999
13.538 | 76 | 76 | 0 | 0 | GC.API.XUnitWrapper.dll
1.225 | 3 | 3 | 0 | 0 | GC.Coverage.XUnitWrapper.dll
183.980 | 42 | 42 | 0 | 0 | GC.Features.XUnitWrapper.dll
3.100 | 6 | 6 | 0 | 0 | GC.LargeMemory.XUnitWrapper.dll
4.731 | 12 | 12 | 0 | 0 | GC.Regressions.XUnitWrapper.dll
22.314 | 481 | 481 | 0 | 0 | GC.Scenarios.XUnitWrapper.dll
0.039 | 1 | 1 | 0 | 0 | GC.Stress.XUnitWrapper.dll
0.534 | 1 | 1 | 0 | 0 | ilasm.PortablePdb.XUnitWrapper.dll
0.619 | 1 | 1 | 0 | 0 | ilasm.System.XUnitWrapper.dll
2.668 | 1 | 1 | 0 | 0 | ilverify.XUnitWrapper.dll
0.537 | 2 | 2 | 0 | 0 | profiler.assembly.XUnitWrapper.dll
1.236 | 2 | 2 | 0 | 0 | profiler.elt.XUnitWrapper.dll
0.793 | 3 | 3 | 0 | 0 | profiler.eventpipe.XUnitWrapper.dll
0.983 | 4 | 4 | 0 | 0 | profiler.gc.XUnitWrapper.dll
0.557 | 1 | 1 | 0 | 0 | profiler.handles.XUnitWrapper.dll
0.038 | 1 | 1 | 0 | 0 | profiler.multiple.XUnitWrapper.dll
0.037 | 1 | 1 | 0 | 0 | profiler.rejit.XUnitWrapper.dll
1.360 | 1 | 1 | 0 | 0 | profiler.transitions.XUnitWrapper.dll
4.133 | 5 | 5 | 0 | 0 | profiler.unittest.XUnitWrapper.dll
0.117 | 1 | 0 | 0 | 1 | JIT.jit64.jit64_2
5.451 | 116 | 116 | 0 | 0 | JIT.SIMD.JIT.SIMD
6.433 | 101 | 101 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests1400-1599
4.025 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests200-299
10.097 | 230 | 227 | 1 | 2 | JIT.Directed.Directed_3
19.526 | 214 | 214 | 0 | 0 | JIT.Directed.Directed_1
5.211 | 216 | 216 | 0 | 0 | JIT.Generics.JIT.Generics
8.080 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests1200-1299
12.593 | 16 | 16 | 0 | 0 | reflection.reflection
138.821 | 100 | 100 | 0 | 0 | JIT.Performance.JIT.performance
172.627 | 11 | 11 | 0 | 0 | JIT.JIT_others
2.365 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests0-99
1.128 | 2 | 1 | 0 | 1 | Exceptions.Exceptions
60.075 | 88 | 88 | 0 | 0 | baseservices.threading.threading_group2
2.885 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests500-599
158.641 | 322 | 321 | 0 | 1 | Loader.Loader
17.855 | 226 | 207 | 0 | 19 | Interop.Interop
5.244 | 437 | 433 | 0 | 4 | JIT.Regression.Regression_6
8.702 | 641 | 641 | 0 | 0 | JIT.CodeGenBringUpTests.JIT.CodeGenBringUpTests
6.596 | 16 | 16 | 0 | 0 | JIT.JIT_r
23.990 | 482 | 480 | 0 | 2 | JIT.Regression.Regression_1
8.302 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests700-799
0.522 | 3 | 3 | 0 | 0 | JIT.JIT_do
9.039 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests1100-1199
2.658 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests400-499
48.146 | 112 | 112 | 0 | 0 | JIT.jit64.jit64_1
84.672 | 1 | 1 | 0 | 0 | readytorun.coreroot_determinism.readytorun_coreroot_determinism
13.396 | 215 | 215 | 0 | 0 | Loader.classloader.generics.LoaderClassloaderGenerics
2.474 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests100-199
43.988 | 2551 | 2551 | 0 | 0 | JIT.HardwareIntrinsics.HardwareIntrinsics_General_ro
9.626 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests1300-1399
76.360 | 75 | 75 | 0 | 0 | Regressions.Regressions
5.244 | 211 | 210 | 0 | 1 | JIT.Methodical.Methodical_r2
5.458 | 85 | 85 | 0 | 0 | JIT.Methodical.Methodical_ro
9.593 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests800-899
75.522 | 20 | 18 | 0 | 2 | readytorun.readytorun
12.881 | 279 | 279 | 0 | 0 | JIT.Methodical.Methodical_r1
3.120 | 343 | 343 | 0 | 0 | JIT.jit64.jit64_4
1.532 | 47 | 47 | 0 | 0 | JIT.Regression.Regression_5
41.352 | 144 | 142 | 0 | 2 | baseservices.exceptions.baseservices-exceptions
9.289 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests1000-1099
18.946 | 67 | 67 | 0 | 0 | Loader.classloader.regressions.LoaderClassloaderRegressions
83.636 | 355 | 353 | 0 | 2 | JIT.opt.JIT.opt
5.979 | 85 | 85 | 0 | 0 | JIT.Methodical.Methodical_do
4.367 | 35 | 33 | 0 | 2 | tracing.tracing
37.561 | 485 | 484 | 0 | 1 | JIT.Regression.Regression_2
13.844 | 276 | 276 | 0 | 0 | JIT.Methodical.Methodical_d1
0.467 | 2 | 2 | 0 | 0 | JIT.JIT_d
92.261 | 143 | 139 | 0 | 4 | JIT.jit64.jit64_3
6.514 | 16 | 16 | 0 | 0 | JIT.JIT_ro
50.519 | 39 | 35 | 0 | 4 | baseservices.baseservices
7.336 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests600-699
5.981 | 208 | 207 | 0 | 1 | JIT.Methodical.Methodical_d2
35.809 | 231 | 226 | 0 | 5 | JIT.jit64.jit64_5
49.200 | 2584 | 2584 | 0 | 0 | JIT.HardwareIntrinsics.HardwareIntrinsics_General_r
1.555 | 55 | 54 | 0 | 1 | JIT.Methodical.Methodical_others
3.838 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests300-399
0.088 | 0 | 0 | 0 | 0 | managed.Managed
54.354 | 203 | 199 | 0 | 4 | JIT.Directed.Directed_2
2.741 | 405 | 405 | 0 | 0 | JIT.IL_Conformance.IL_Conformance
77.532 | 82 | 81 | 0 | 1 | baseservices.threading.threading_group1
----------------------------------------------------------------------------
1997.991 | 15149 | 15085 | 1 | 63 | (total)

That single failure I get on latest head, so I'm not worried about it.

Comment threadsrc/coreclr/pal/src/arch/arm64/context2.S
@jkotas

Copy link
Copy Markdown
Member

I see a lot of TODOs about SVE size being hardcoded to 128 bit.

What is going to be the experience when somebody runs .NET 9 binary on a machine with 256 bit SVE? It is important that it just works, without crashing, buffer overruns, etc.

@a74nh

Copy link
Copy Markdown
ContributorAuthor

I see a lot of TODOs about SVE size being hardcoded to 128 bit.

What is going to be the experience when somebody runs .NET 9 binary on a machine with 256 bit SVE? It is important that it just works, without crashing, buffer overruns, etc.

Running the entire testsuite on 256bit, all the tests pass with and without my latest fix. That's because there is no SVE state in the kernel, so that structure that comes back from the OS has no SVE state (sve.size is 16, it's just the header with no data).

Comment threadsrc/coreclr/pal/src/arch/arm64/asmconstants.h

@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.

Thanks @a74nh for your contribution. LGTM.

@kunalspathak

Copy link
Copy Markdown
Contributor

/ba-g failure is #103550

@kunalspathak
kunalspathak merged commit 9528c15 into dotnet:mainJun 29, 2024
akoeplinger added a commit to akoeplinger/runtime that referenced this pull request Jul 8, 2024
It got broken by dotnet#103801 due to a host vs. target arch typo.
This showed up in the VMR since we use arm64 macOS build agents there.
akoeplinger added a commit to akoeplinger/runtime that referenced this pull request Jul 8, 2024
It got uncovered by dotnet#103801.
This showed up in the VMR since we use arm64 macOS build agents there.
akoeplinger added a commit that referenced this pull request Jul 8, 2024
It got uncovered by #103801.
This showed up in the VMR since we use arm64 macOS build agents there.
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jul 29, 2024
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-PAL-coreclronly for closed issuesarm-sveWork related to arm64 SVE/SVE2 supportcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@a74nh@kunalspathak@janvorli@jkotas@JasonLinMS
, '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

ARM64-SVE: Add SVE registers to pal context - #103801

Merged
kunalspathak merged 29 commits into
dotnet:mainfrom
a74nh:sve_state_github
Jun 29, 2024
Merged

ARM64-SVE: Add SVE registers to pal context#103801
kunalspathak merged 29 commits into
dotnet:mainfrom
a74nh:sve_state_github

Conversation

@a74nh

@a74nha74nh commented Jun 21, 2024

Copy link
Copy Markdown
Contributor

Adds Linux support for SVE state on signals.

Testing:
I forced a sigill (by making one of the hwintrinsic API calls generate a bad instruction). I checked the SVE registers when the signal occurred. I stepped through and made sure the lpContext is correctly filled.

@ghostghost added the area-PAL-coreclr only for closed issues label Jun 21, 2024
@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Jun 21, 2024
Comment threadsrc/coreclr/pal/inc/pal.h Outdated
//
// Sve Registers
//
//TODO-SVE: How does this structure handle variable sized Z/P/FFR registers?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

AIUI, this should match the same structure in Windows. I don't have the any documentation, so I've made a guess at what the fields should be for SVE, and I expect that it's wrong
For convenience I've only used a vector length 128bits. I'd be surprised if windows supports a full 2048bit vector length without doing anything special.
(Offsets below marked with a ? I'll fix once the structure is correct)

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.

Windows in general don't store extended context parts in the CONTEXT data structure itself. There is a flag CONTEXT_XSTATE that indicates presence of extra data attached to the CONTEXT. There are APIs InitializeContext and InitializeContext2 that allows setting up a context for the extended state. It can be also used to get the size of memory needed for the extended context. The InitializeContext2 is a new one that allows to select only a subset of the extended state using the XStateCompactionMask argument.

We have done this differently for AVX512 for the sake of simplicity - we have included the extra registers in the CONTEXT structure itself. I think it would be better to move that to the way Windows handle that so that we don't waste time initializing and copying extra fields at places where we don't care about the extended state or when the current CPU doesn't support them. That would also allow to size the storage for the Z/P registers dynamically based on the current CPU.
Having said that though, for this PR, we can follow the suite and do the same thing we did for intel avx512 and migrate both to the better model later. Based on what @kunalspathak told me, starting with 128 bits of space for the registers should be sufficient for now.

I would add them to the very end of the CONTEXT after the debug registers so that the layout of the part that's common with Windows is the same.

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.

Yep, for the OS, extended context like SVE and AVX etc are stored in a variable-sized buffer separate from the CONTEXT. The CONTEXT_EX structure immediately follows the CONTEXT structure, and contains pointers to the variable-sized XSTATE buffer. On x64, the XSTATE buffer is in the exact format that is supported by the hardware via the XSAVE and XRSTOR instructions. On ARM64, there are no XSAVE/XRSTOR instructions, but the XSTATE buffer is laid out in a similar fashion to x64 (including Header->Mask, Header->CompationMask etc), to allow for max code sharing with x64.

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.

The OS kernel does support all SVE vector lengths, up to 2048-bit SVE, though there is the caveat that HyperV only supports 128-bit SVE. So, when running on hardware that supports SVE larger than 128-bits, if HyperV is enabled you'll only see 128-bit SVE, but if HyperV is off then you'll be able to take advantage of the full SVE width supported by the CPU. And to my understanding, there is likely hardware in the future that supports larger SVE lengths than 128-bit, though I don't know any specific on timelines.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks for the comments. Updated with the following:

  • Added context2.S changes
  • Removed store/restore of Z registers (as we only support 128bits for now, which fully overlap the V registers)
  • Added a XStateFeaturesMask to the Arm64 context so that we can tell whether to use SVE or not.

I'm currently unsure where else SVE state might need saving/restoring

@a74nh

Copy link
Copy Markdown
ContributorAuthor

Things I'm unsure about:

  • What the LPCONTEXT should look like
  • If there are extra areas in coreclr that need covering
    • I think AOT needs convering too. But SVE is no yet supported in AOT
    • Do the SVE registers need propagating anywhere else?
  • Is there a testsuite for this?

@a74nh
a74nh marked this pull request as ready for review June 21, 2024 13:22
@a74nh

Copy link
Copy Markdown
ContributorAuthor

Build failures on Windows, but I expected that as that all still needs doing. Marking as ready as I could do with comments, especially on the Windows side.

@dotnet/arm64-contrib @kunalspathak@tannergooding

@kunalspathakkunalspathak added the arm-sve Work related to arm64 SVE/SVE2 support label Jun 21, 2024
@kunalspathak

Copy link
Copy Markdown
Contributor

@JasonLinMS

Comment threadsrc/coreclr/debug/inc/dbgtargetcontext.h Outdated
Comment threadsrc/coreclr/pal/inc/pal.h Outdated
Comment threadsrc/coreclr/pal/src/arch/arm64/context2.S Outdated
}
}

if (sve)

@janvorlijanvorliJun 27, 2024

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.

Similar to x64, we should copy the state only if the contextFlags has the CONTEXT_XSTATE flag set. The passed in contextFlags list parts of the state that are valid that the caller is interested in.

It seems it would make sense to move this to the end of the function next to where we extract xstate for amd64 and put it under the same if ((contextFlags & CONTEXT_XSTATE) == CONTEXT_XSTATE).

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Similar to x64, we should copy the state only if the contextFlags has the CONTEXT_XSTATE flag set.

There is one remaining test failure I've just debugged to being due to this. Will fix it up.

sub x0, x0, CONTEXT_FLOAT_CONTROL_OFFSET + CONTEXT_NEON_OFFSET

LOCAL_LABEL(Done_CONTEXT_FLOATING_POINT):
ldr x1, [x0, CONTEXT_XSTATEFEATURESMASK_OFFSET]

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.

It should check the CONTEXT_XSTATE in CONTEXT_ContextFlags first and check the features mask only if the CONTEXT_XSTATE is set.

// since we potentially clobber x0 below, we'll bank it in x16
mov x16, x0

ldr w17, [x16, CONTEXT_XSTATEFEATURESMASK_OFFSET]

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.

It should check the CONTEXT_XSTATE in CONTEXT_ContextFlags first and check the features mask only if the CONTEXT_XSTATE is set.

#endif // XSTATE_SUPPORTED || (HOST_AMD64 && HAVE_MACH_EXCEPTIONS)

#if defined(HOST_64BIT) && defined(HOST_ARM64) && !defined(TARGET_FREEBSD) && !defined(TARGET_OSX)
#if !defined(SVE_MAGIC)

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.

Is this define not present when building in our CI?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Is this define not present when building in our CI?

Yes, they are missing in the CI. If I remove any of them the build falls over. I think this is when cross compiling. Eithe way, it must be an old Linux being used because these defines have been present in Linux since about 2017.

@janvorli

Copy link
Copy Markdown
Member

Besides the few comments, it looks good.

@a74nh

Copy link
Copy Markdown
ContributorAuthor

Fixed up so that XSTATE is set and checked as suggested.
Everything in run.sh passes and I can see state getting copied when debugging around signals.

This PR enables -DXSTATE_SUPPORTED on Arm64. Am I correct in thinking that on AMD64 Windows this flag is also used in certain scenarios to ensure the xstate data is block copied? If that is the case, then on Arm64 Windows this support still needs adding - probably by just enabling some AMD64 defines for ARM64. However, I've not go a windows setup and so don't want to blindly do anything here and recommend someone checks windows this after this PR is merged.

@a74nh

Copy link
Copy Markdown
ContributorAuthor

Running all priority 1 tests in checked on SVE Linux....

Time [secs] | Total | Passed | Failed | Skipped | Assembly Execution Summary
============================================================================
30.836 | 131 | 131 | 0 | 0 | JIT.Regression.Regression_4
13.873 | 345 | 342 | 0 | 3 | JIT.Regression.Regression_3
13.446 | 53 | 53 | 0 | 0 | CoreMangLib.CoreMangLib
11.249 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests900-999
13.538 | 76 | 76 | 0 | 0 | GC.API.XUnitWrapper.dll
1.225 | 3 | 3 | 0 | 0 | GC.Coverage.XUnitWrapper.dll
183.980 | 42 | 42 | 0 | 0 | GC.Features.XUnitWrapper.dll
3.100 | 6 | 6 | 0 | 0 | GC.LargeMemory.XUnitWrapper.dll
4.731 | 12 | 12 | 0 | 0 | GC.Regressions.XUnitWrapper.dll
22.314 | 481 | 481 | 0 | 0 | GC.Scenarios.XUnitWrapper.dll
0.039 | 1 | 1 | 0 | 0 | GC.Stress.XUnitWrapper.dll
0.534 | 1 | 1 | 0 | 0 | ilasm.PortablePdb.XUnitWrapper.dll
0.619 | 1 | 1 | 0 | 0 | ilasm.System.XUnitWrapper.dll
2.668 | 1 | 1 | 0 | 0 | ilverify.XUnitWrapper.dll
0.537 | 2 | 2 | 0 | 0 | profiler.assembly.XUnitWrapper.dll
1.236 | 2 | 2 | 0 | 0 | profiler.elt.XUnitWrapper.dll
0.793 | 3 | 3 | 0 | 0 | profiler.eventpipe.XUnitWrapper.dll
0.983 | 4 | 4 | 0 | 0 | profiler.gc.XUnitWrapper.dll
0.557 | 1 | 1 | 0 | 0 | profiler.handles.XUnitWrapper.dll
0.038 | 1 | 1 | 0 | 0 | profiler.multiple.XUnitWrapper.dll
0.037 | 1 | 1 | 0 | 0 | profiler.rejit.XUnitWrapper.dll
1.360 | 1 | 1 | 0 | 0 | profiler.transitions.XUnitWrapper.dll
4.133 | 5 | 5 | 0 | 0 | profiler.unittest.XUnitWrapper.dll
0.117 | 1 | 0 | 0 | 1 | JIT.jit64.jit64_2
5.451 | 116 | 116 | 0 | 0 | JIT.SIMD.JIT.SIMD
6.433 | 101 | 101 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests1400-1599
4.025 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests200-299
10.097 | 230 | 227 | 1 | 2 | JIT.Directed.Directed_3
19.526 | 214 | 214 | 0 | 0 | JIT.Directed.Directed_1
5.211 | 216 | 216 | 0 | 0 | JIT.Generics.JIT.Generics
8.080 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests1200-1299
12.593 | 16 | 16 | 0 | 0 | reflection.reflection
138.821 | 100 | 100 | 0 | 0 | JIT.Performance.JIT.performance
172.627 | 11 | 11 | 0 | 0 | JIT.JIT_others
2.365 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests0-99
1.128 | 2 | 1 | 0 | 1 | Exceptions.Exceptions
60.075 | 88 | 88 | 0 | 0 | baseservices.threading.threading_group2
2.885 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests500-599
158.641 | 322 | 321 | 0 | 1 | Loader.Loader
17.855 | 226 | 207 | 0 | 19 | Interop.Interop
5.244 | 437 | 433 | 0 | 4 | JIT.Regression.Regression_6
8.702 | 641 | 641 | 0 | 0 | JIT.CodeGenBringUpTests.JIT.CodeGenBringUpTests
6.596 | 16 | 16 | 0 | 0 | JIT.JIT_r
23.990 | 482 | 480 | 0 | 2 | JIT.Regression.Regression_1
8.302 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests700-799
0.522 | 3 | 3 | 0 | 0 | JIT.JIT_do
9.039 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests1100-1199
2.658 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests400-499
48.146 | 112 | 112 | 0 | 0 | JIT.jit64.jit64_1
84.672 | 1 | 1 | 0 | 0 | readytorun.coreroot_determinism.readytorun_coreroot_determinism
13.396 | 215 | 215 | 0 | 0 | Loader.classloader.generics.LoaderClassloaderGenerics
2.474 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests100-199
43.988 | 2551 | 2551 | 0 | 0 | JIT.HardwareIntrinsics.HardwareIntrinsics_General_ro
9.626 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests1300-1399
76.360 | 75 | 75 | 0 | 0 | Regressions.Regressions
5.244 | 211 | 210 | 0 | 1 | JIT.Methodical.Methodical_r2
5.458 | 85 | 85 | 0 | 0 | JIT.Methodical.Methodical_ro
9.593 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests800-899
75.522 | 20 | 18 | 0 | 2 | readytorun.readytorun
12.881 | 279 | 279 | 0 | 0 | JIT.Methodical.Methodical_r1
3.120 | 343 | 343 | 0 | 0 | JIT.jit64.jit64_4
1.532 | 47 | 47 | 0 | 0 | JIT.Regression.Regression_5
41.352 | 144 | 142 | 0 | 2 | baseservices.exceptions.baseservices-exceptions
9.289 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests1000-1099
18.946 | 67 | 67 | 0 | 0 | Loader.classloader.regressions.LoaderClassloaderRegressions
83.636 | 355 | 353 | 0 | 2 | JIT.opt.JIT.opt
5.979 | 85 | 85 | 0 | 0 | JIT.Methodical.Methodical_do
4.367 | 35 | 33 | 0 | 2 | tracing.tracing
37.561 | 485 | 484 | 0 | 1 | JIT.Regression.Regression_2
13.844 | 276 | 276 | 0 | 0 | JIT.Methodical.Methodical_d1
0.467 | 2 | 2 | 0 | 0 | JIT.JIT_d
92.261 | 143 | 139 | 0 | 4 | JIT.jit64.jit64_3
6.514 | 16 | 16 | 0 | 0 | JIT.JIT_ro
50.519 | 39 | 35 | 0 | 4 | baseservices.baseservices
7.336 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests600-699
5.981 | 208 | 207 | 0 | 1 | JIT.Methodical.Methodical_d2
35.809 | 231 | 226 | 0 | 5 | JIT.jit64.jit64_5
49.200 | 2584 | 2584 | 0 | 0 | JIT.HardwareIntrinsics.HardwareIntrinsics_General_r
1.555 | 55 | 54 | 0 | 1 | JIT.Methodical.Methodical_others
3.838 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests300-399
0.088 | 0 | 0 | 0 | 0 | managed.Managed
54.354 | 203 | 199 | 0 | 4 | JIT.Directed.Directed_2
2.741 | 405 | 405 | 0 | 0 | JIT.IL_Conformance.IL_Conformance
77.532 | 82 | 81 | 0 | 1 | baseservices.threading.threading_group1
----------------------------------------------------------------------------
1997.991 | 15149 | 15085 | 1 | 63 | (total)

That single failure I get on latest head, so I'm not worried about it.

Comment threadsrc/coreclr/pal/src/arch/arm64/context2.S
@jkotas

Copy link
Copy Markdown
Member

I see a lot of TODOs about SVE size being hardcoded to 128 bit.

What is going to be the experience when somebody runs .NET 9 binary on a machine with 256 bit SVE? It is important that it just works, without crashing, buffer overruns, etc.

@a74nh

Copy link
Copy Markdown
ContributorAuthor

I see a lot of TODOs about SVE size being hardcoded to 128 bit.

What is going to be the experience when somebody runs .NET 9 binary on a machine with 256 bit SVE? It is important that it just works, without crashing, buffer overruns, etc.

Running the entire testsuite on 256bit, all the tests pass with and without my latest fix. That's because there is no SVE state in the kernel, so that structure that comes back from the OS has no SVE state (sve.size is 16, it's just the header with no data).

Comment threadsrc/coreclr/pal/src/arch/arm64/asmconstants.h

@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.

Thanks @a74nh for your contribution. LGTM.

@kunalspathak

Copy link
Copy Markdown
Contributor

/ba-g failure is #103550

@kunalspathak
kunalspathak merged commit 9528c15 into dotnet:mainJun 29, 2024
akoeplinger added a commit to akoeplinger/runtime that referenced this pull request Jul 8, 2024
It got broken by dotnet#103801 due to a host vs. target arch typo.
This showed up in the VMR since we use arm64 macOS build agents there.
akoeplinger added a commit to akoeplinger/runtime that referenced this pull request Jul 8, 2024
It got uncovered by dotnet#103801.
This showed up in the VMR since we use arm64 macOS build agents there.
akoeplinger added a commit that referenced this pull request Jul 8, 2024
It got uncovered by #103801.
This showed up in the VMR since we use arm64 macOS build agents there.
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jul 29, 2024
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-PAL-coreclronly for closed issuesarm-sveWork related to arm64 SVE/SVE2 supportcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@a74nh@kunalspathak@janvorli@jkotas@JasonLinMS
, '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

ARM64-SVE: Add SVE registers to pal context - #103801

Merged
kunalspathak merged 29 commits into
dotnet:mainfrom
a74nh:sve_state_github
Jun 29, 2024
Merged

ARM64-SVE: Add SVE registers to pal context#103801
kunalspathak merged 29 commits into
dotnet:mainfrom
a74nh:sve_state_github

Conversation

@a74nh

@a74nha74nh commented Jun 21, 2024

Copy link
Copy Markdown
Contributor

Adds Linux support for SVE state on signals.

Testing:
I forced a sigill (by making one of the hwintrinsic API calls generate a bad instruction). I checked the SVE registers when the signal occurred. I stepped through and made sure the lpContext is correctly filled.

@ghostghost added the area-PAL-coreclr only for closed issues label Jun 21, 2024
@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Jun 21, 2024
Comment threadsrc/coreclr/pal/inc/pal.h Outdated
//
// Sve Registers
//
//TODO-SVE: How does this structure handle variable sized Z/P/FFR registers?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

AIUI, this should match the same structure in Windows. I don't have the any documentation, so I've made a guess at what the fields should be for SVE, and I expect that it's wrong
For convenience I've only used a vector length 128bits. I'd be surprised if windows supports a full 2048bit vector length without doing anything special.
(Offsets below marked with a ? I'll fix once the structure is correct)

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.

Windows in general don't store extended context parts in the CONTEXT data structure itself. There is a flag CONTEXT_XSTATE that indicates presence of extra data attached to the CONTEXT. There are APIs InitializeContext and InitializeContext2 that allows setting up a context for the extended state. It can be also used to get the size of memory needed for the extended context. The InitializeContext2 is a new one that allows to select only a subset of the extended state using the XStateCompactionMask argument.

We have done this differently for AVX512 for the sake of simplicity - we have included the extra registers in the CONTEXT structure itself. I think it would be better to move that to the way Windows handle that so that we don't waste time initializing and copying extra fields at places where we don't care about the extended state or when the current CPU doesn't support them. That would also allow to size the storage for the Z/P registers dynamically based on the current CPU.
Having said that though, for this PR, we can follow the suite and do the same thing we did for intel avx512 and migrate both to the better model later. Based on what @kunalspathak told me, starting with 128 bits of space for the registers should be sufficient for now.

I would add them to the very end of the CONTEXT after the debug registers so that the layout of the part that's common with Windows is the same.

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.

Yep, for the OS, extended context like SVE and AVX etc are stored in a variable-sized buffer separate from the CONTEXT. The CONTEXT_EX structure immediately follows the CONTEXT structure, and contains pointers to the variable-sized XSTATE buffer. On x64, the XSTATE buffer is in the exact format that is supported by the hardware via the XSAVE and XRSTOR instructions. On ARM64, there are no XSAVE/XRSTOR instructions, but the XSTATE buffer is laid out in a similar fashion to x64 (including Header->Mask, Header->CompationMask etc), to allow for max code sharing with x64.

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.

The OS kernel does support all SVE vector lengths, up to 2048-bit SVE, though there is the caveat that HyperV only supports 128-bit SVE. So, when running on hardware that supports SVE larger than 128-bits, if HyperV is enabled you'll only see 128-bit SVE, but if HyperV is off then you'll be able to take advantage of the full SVE width supported by the CPU. And to my understanding, there is likely hardware in the future that supports larger SVE lengths than 128-bit, though I don't know any specific on timelines.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks for the comments. Updated with the following:

  • Added context2.S changes
  • Removed store/restore of Z registers (as we only support 128bits for now, which fully overlap the V registers)
  • Added a XStateFeaturesMask to the Arm64 context so that we can tell whether to use SVE or not.

I'm currently unsure where else SVE state might need saving/restoring

@a74nh

Copy link
Copy Markdown
ContributorAuthor

Things I'm unsure about:

  • What the LPCONTEXT should look like
  • If there are extra areas in coreclr that need covering
    • I think AOT needs convering too. But SVE is no yet supported in AOT
    • Do the SVE registers need propagating anywhere else?
  • Is there a testsuite for this?

@a74nh
a74nh marked this pull request as ready for review June 21, 2024 13:22
@a74nh

Copy link
Copy Markdown
ContributorAuthor

Build failures on Windows, but I expected that as that all still needs doing. Marking as ready as I could do with comments, especially on the Windows side.

@dotnet/arm64-contrib @kunalspathak@tannergooding

@kunalspathakkunalspathak added the arm-sve Work related to arm64 SVE/SVE2 support label Jun 21, 2024
@kunalspathak

Copy link
Copy Markdown
Contributor

@JasonLinMS

Comment threadsrc/coreclr/debug/inc/dbgtargetcontext.h Outdated
Comment threadsrc/coreclr/pal/inc/pal.h Outdated
Comment threadsrc/coreclr/pal/src/arch/arm64/context2.S Outdated
}
}

if (sve)

@janvorlijanvorliJun 27, 2024

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.

Similar to x64, we should copy the state only if the contextFlags has the CONTEXT_XSTATE flag set. The passed in contextFlags list parts of the state that are valid that the caller is interested in.

It seems it would make sense to move this to the end of the function next to where we extract xstate for amd64 and put it under the same if ((contextFlags & CONTEXT_XSTATE) == CONTEXT_XSTATE).

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Similar to x64, we should copy the state only if the contextFlags has the CONTEXT_XSTATE flag set.

There is one remaining test failure I've just debugged to being due to this. Will fix it up.

sub x0, x0, CONTEXT_FLOAT_CONTROL_OFFSET + CONTEXT_NEON_OFFSET

LOCAL_LABEL(Done_CONTEXT_FLOATING_POINT):
ldr x1, [x0, CONTEXT_XSTATEFEATURESMASK_OFFSET]

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.

It should check the CONTEXT_XSTATE in CONTEXT_ContextFlags first and check the features mask only if the CONTEXT_XSTATE is set.

// since we potentially clobber x0 below, we'll bank it in x16
mov x16, x0

ldr w17, [x16, CONTEXT_XSTATEFEATURESMASK_OFFSET]

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.

It should check the CONTEXT_XSTATE in CONTEXT_ContextFlags first and check the features mask only if the CONTEXT_XSTATE is set.

#endif // XSTATE_SUPPORTED || (HOST_AMD64 && HAVE_MACH_EXCEPTIONS)

#if defined(HOST_64BIT) && defined(HOST_ARM64) && !defined(TARGET_FREEBSD) && !defined(TARGET_OSX)
#if !defined(SVE_MAGIC)

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.

Is this define not present when building in our CI?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Is this define not present when building in our CI?

Yes, they are missing in the CI. If I remove any of them the build falls over. I think this is when cross compiling. Eithe way, it must be an old Linux being used because these defines have been present in Linux since about 2017.

@janvorli

Copy link
Copy Markdown
Member

Besides the few comments, it looks good.

@a74nh

Copy link
Copy Markdown
ContributorAuthor

Fixed up so that XSTATE is set and checked as suggested.
Everything in run.sh passes and I can see state getting copied when debugging around signals.

This PR enables -DXSTATE_SUPPORTED on Arm64. Am I correct in thinking that on AMD64 Windows this flag is also used in certain scenarios to ensure the xstate data is block copied? If that is the case, then on Arm64 Windows this support still needs adding - probably by just enabling some AMD64 defines for ARM64. However, I've not go a windows setup and so don't want to blindly do anything here and recommend someone checks windows this after this PR is merged.

@a74nh

Copy link
Copy Markdown
ContributorAuthor

Running all priority 1 tests in checked on SVE Linux....

Time [secs] | Total | Passed | Failed | Skipped | Assembly Execution Summary
============================================================================
30.836 | 131 | 131 | 0 | 0 | JIT.Regression.Regression_4
13.873 | 345 | 342 | 0 | 3 | JIT.Regression.Regression_3
13.446 | 53 | 53 | 0 | 0 | CoreMangLib.CoreMangLib
11.249 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests900-999
13.538 | 76 | 76 | 0 | 0 | GC.API.XUnitWrapper.dll
1.225 | 3 | 3 | 0 | 0 | GC.Coverage.XUnitWrapper.dll
183.980 | 42 | 42 | 0 | 0 | GC.Features.XUnitWrapper.dll
3.100 | 6 | 6 | 0 | 0 | GC.LargeMemory.XUnitWrapper.dll
4.731 | 12 | 12 | 0 | 0 | GC.Regressions.XUnitWrapper.dll
22.314 | 481 | 481 | 0 | 0 | GC.Scenarios.XUnitWrapper.dll
0.039 | 1 | 1 | 0 | 0 | GC.Stress.XUnitWrapper.dll
0.534 | 1 | 1 | 0 | 0 | ilasm.PortablePdb.XUnitWrapper.dll
0.619 | 1 | 1 | 0 | 0 | ilasm.System.XUnitWrapper.dll
2.668 | 1 | 1 | 0 | 0 | ilverify.XUnitWrapper.dll
0.537 | 2 | 2 | 0 | 0 | profiler.assembly.XUnitWrapper.dll
1.236 | 2 | 2 | 0 | 0 | profiler.elt.XUnitWrapper.dll
0.793 | 3 | 3 | 0 | 0 | profiler.eventpipe.XUnitWrapper.dll
0.983 | 4 | 4 | 0 | 0 | profiler.gc.XUnitWrapper.dll
0.557 | 1 | 1 | 0 | 0 | profiler.handles.XUnitWrapper.dll
0.038 | 1 | 1 | 0 | 0 | profiler.multiple.XUnitWrapper.dll
0.037 | 1 | 1 | 0 | 0 | profiler.rejit.XUnitWrapper.dll
1.360 | 1 | 1 | 0 | 0 | profiler.transitions.XUnitWrapper.dll
4.133 | 5 | 5 | 0 | 0 | profiler.unittest.XUnitWrapper.dll
0.117 | 1 | 0 | 0 | 1 | JIT.jit64.jit64_2
5.451 | 116 | 116 | 0 | 0 | JIT.SIMD.JIT.SIMD
6.433 | 101 | 101 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests1400-1599
4.025 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests200-299
10.097 | 230 | 227 | 1 | 2 | JIT.Directed.Directed_3
19.526 | 214 | 214 | 0 | 0 | JIT.Directed.Directed_1
5.211 | 216 | 216 | 0 | 0 | JIT.Generics.JIT.Generics
8.080 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests1200-1299
12.593 | 16 | 16 | 0 | 0 | reflection.reflection
138.821 | 100 | 100 | 0 | 0 | JIT.Performance.JIT.performance
172.627 | 11 | 11 | 0 | 0 | JIT.JIT_others
2.365 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests0-99
1.128 | 2 | 1 | 0 | 1 | Exceptions.Exceptions
60.075 | 88 | 88 | 0 | 0 | baseservices.threading.threading_group2
2.885 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests500-599
158.641 | 322 | 321 | 0 | 1 | Loader.Loader
17.855 | 226 | 207 | 0 | 19 | Interop.Interop
5.244 | 437 | 433 | 0 | 4 | JIT.Regression.Regression_6
8.702 | 641 | 641 | 0 | 0 | JIT.CodeGenBringUpTests.JIT.CodeGenBringUpTests
6.596 | 16 | 16 | 0 | 0 | JIT.JIT_r
23.990 | 482 | 480 | 0 | 2 | JIT.Regression.Regression_1
8.302 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests700-799
0.522 | 3 | 3 | 0 | 0 | JIT.JIT_do
9.039 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests1100-1199
2.658 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests400-499
48.146 | 112 | 112 | 0 | 0 | JIT.jit64.jit64_1
84.672 | 1 | 1 | 0 | 0 | readytorun.coreroot_determinism.readytorun_coreroot_determinism
13.396 | 215 | 215 | 0 | 0 | Loader.classloader.generics.LoaderClassloaderGenerics
2.474 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests100-199
43.988 | 2551 | 2551 | 0 | 0 | JIT.HardwareIntrinsics.HardwareIntrinsics_General_ro
9.626 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests1300-1399
76.360 | 75 | 75 | 0 | 0 | Regressions.Regressions
5.244 | 211 | 210 | 0 | 1 | JIT.Methodical.Methodical_r2
5.458 | 85 | 85 | 0 | 0 | JIT.Methodical.Methodical_ro
9.593 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests800-899
75.522 | 20 | 18 | 0 | 2 | readytorun.readytorun
12.881 | 279 | 279 | 0 | 0 | JIT.Methodical.Methodical_r1
3.120 | 343 | 343 | 0 | 0 | JIT.jit64.jit64_4
1.532 | 47 | 47 | 0 | 0 | JIT.Regression.Regression_5
41.352 | 144 | 142 | 0 | 2 | baseservices.exceptions.baseservices-exceptions
9.289 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests1000-1099
18.946 | 67 | 67 | 0 | 0 | Loader.classloader.regressions.LoaderClassloaderRegressions
83.636 | 355 | 353 | 0 | 2 | JIT.opt.JIT.opt
5.979 | 85 | 85 | 0 | 0 | JIT.Methodical.Methodical_do
4.367 | 35 | 33 | 0 | 2 | tracing.tracing
37.561 | 485 | 484 | 0 | 1 | JIT.Regression.Regression_2
13.844 | 276 | 276 | 0 | 0 | JIT.Methodical.Methodical_d1
0.467 | 2 | 2 | 0 | 0 | JIT.JIT_d
92.261 | 143 | 139 | 0 | 4 | JIT.jit64.jit64_3
6.514 | 16 | 16 | 0 | 0 | JIT.JIT_ro
50.519 | 39 | 35 | 0 | 4 | baseservices.baseservices
7.336 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests600-699
5.981 | 208 | 207 | 0 | 1 | JIT.Methodical.Methodical_d2
35.809 | 231 | 226 | 0 | 5 | JIT.jit64.jit64_5
49.200 | 2584 | 2584 | 0 | 0 | JIT.HardwareIntrinsics.HardwareIntrinsics_General_r
1.555 | 55 | 54 | 0 | 1 | JIT.Methodical.Methodical_others
3.838 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests300-399
0.088 | 0 | 0 | 0 | 0 | managed.Managed
54.354 | 203 | 199 | 0 | 4 | JIT.Directed.Directed_2
2.741 | 405 | 405 | 0 | 0 | JIT.IL_Conformance.IL_Conformance
77.532 | 82 | 81 | 0 | 1 | baseservices.threading.threading_group1
----------------------------------------------------------------------------
1997.991 | 15149 | 15085 | 1 | 63 | (total)

That single failure I get on latest head, so I'm not worried about it.

Comment threadsrc/coreclr/pal/src/arch/arm64/context2.S
@jkotas

Copy link
Copy Markdown
Member

I see a lot of TODOs about SVE size being hardcoded to 128 bit.

What is going to be the experience when somebody runs .NET 9 binary on a machine with 256 bit SVE? It is important that it just works, without crashing, buffer overruns, etc.

@a74nh

Copy link
Copy Markdown
ContributorAuthor

I see a lot of TODOs about SVE size being hardcoded to 128 bit.

What is going to be the experience when somebody runs .NET 9 binary on a machine with 256 bit SVE? It is important that it just works, without crashing, buffer overruns, etc.

Running the entire testsuite on 256bit, all the tests pass with and without my latest fix. That's because there is no SVE state in the kernel, so that structure that comes back from the OS has no SVE state (sve.size is 16, it's just the header with no data).

Comment threadsrc/coreclr/pal/src/arch/arm64/asmconstants.h

@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.

Thanks @a74nh for your contribution. LGTM.

@kunalspathak

Copy link
Copy Markdown
Contributor

/ba-g failure is #103550

@kunalspathak
kunalspathak merged commit 9528c15 into dotnet:mainJun 29, 2024
akoeplinger added a commit to akoeplinger/runtime that referenced this pull request Jul 8, 2024
It got broken by dotnet#103801 due to a host vs. target arch typo.
This showed up in the VMR since we use arm64 macOS build agents there.
akoeplinger added a commit to akoeplinger/runtime that referenced this pull request Jul 8, 2024
It got uncovered by dotnet#103801.
This showed up in the VMR since we use arm64 macOS build agents there.
akoeplinger added a commit that referenced this pull request Jul 8, 2024
It got uncovered by #103801.
This showed up in the VMR since we use arm64 macOS build agents there.
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jul 29, 2024
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-PAL-coreclronly for closed issuesarm-sveWork related to arm64 SVE/SVE2 supportcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@a74nh@kunalspathak@janvorli@jkotas@JasonLinMS
, '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

ARM64-SVE: Add SVE registers to pal context - #103801

Merged
kunalspathak merged 29 commits into
dotnet:mainfrom
a74nh:sve_state_github
Jun 29, 2024
Merged

ARM64-SVE: Add SVE registers to pal context#103801
kunalspathak merged 29 commits into
dotnet:mainfrom
a74nh:sve_state_github

Conversation

@a74nh

@a74nha74nh commented Jun 21, 2024

Copy link
Copy Markdown
Contributor

Adds Linux support for SVE state on signals.

Testing:
I forced a sigill (by making one of the hwintrinsic API calls generate a bad instruction). I checked the SVE registers when the signal occurred. I stepped through and made sure the lpContext is correctly filled.

@ghostghost added the area-PAL-coreclr only for closed issues label Jun 21, 2024
@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Jun 21, 2024
Comment threadsrc/coreclr/pal/inc/pal.h Outdated
//
// Sve Registers
//
//TODO-SVE: How does this structure handle variable sized Z/P/FFR registers?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

AIUI, this should match the same structure in Windows. I don't have the any documentation, so I've made a guess at what the fields should be for SVE, and I expect that it's wrong
For convenience I've only used a vector length 128bits. I'd be surprised if windows supports a full 2048bit vector length without doing anything special.
(Offsets below marked with a ? I'll fix once the structure is correct)

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.

Windows in general don't store extended context parts in the CONTEXT data structure itself. There is a flag CONTEXT_XSTATE that indicates presence of extra data attached to the CONTEXT. There are APIs InitializeContext and InitializeContext2 that allows setting up a context for the extended state. It can be also used to get the size of memory needed for the extended context. The InitializeContext2 is a new one that allows to select only a subset of the extended state using the XStateCompactionMask argument.

We have done this differently for AVX512 for the sake of simplicity - we have included the extra registers in the CONTEXT structure itself. I think it would be better to move that to the way Windows handle that so that we don't waste time initializing and copying extra fields at places where we don't care about the extended state or when the current CPU doesn't support them. That would also allow to size the storage for the Z/P registers dynamically based on the current CPU.
Having said that though, for this PR, we can follow the suite and do the same thing we did for intel avx512 and migrate both to the better model later. Based on what @kunalspathak told me, starting with 128 bits of space for the registers should be sufficient for now.

I would add them to the very end of the CONTEXT after the debug registers so that the layout of the part that's common with Windows is the same.

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.

Yep, for the OS, extended context like SVE and AVX etc are stored in a variable-sized buffer separate from the CONTEXT. The CONTEXT_EX structure immediately follows the CONTEXT structure, and contains pointers to the variable-sized XSTATE buffer. On x64, the XSTATE buffer is in the exact format that is supported by the hardware via the XSAVE and XRSTOR instructions. On ARM64, there are no XSAVE/XRSTOR instructions, but the XSTATE buffer is laid out in a similar fashion to x64 (including Header->Mask, Header->CompationMask etc), to allow for max code sharing with x64.

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.

The OS kernel does support all SVE vector lengths, up to 2048-bit SVE, though there is the caveat that HyperV only supports 128-bit SVE. So, when running on hardware that supports SVE larger than 128-bits, if HyperV is enabled you'll only see 128-bit SVE, but if HyperV is off then you'll be able to take advantage of the full SVE width supported by the CPU. And to my understanding, there is likely hardware in the future that supports larger SVE lengths than 128-bit, though I don't know any specific on timelines.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks for the comments. Updated with the following:

  • Added context2.S changes
  • Removed store/restore of Z registers (as we only support 128bits for now, which fully overlap the V registers)
  • Added a XStateFeaturesMask to the Arm64 context so that we can tell whether to use SVE or not.

I'm currently unsure where else SVE state might need saving/restoring

@a74nh

Copy link
Copy Markdown
ContributorAuthor

Things I'm unsure about:

  • What the LPCONTEXT should look like
  • If there are extra areas in coreclr that need covering
    • I think AOT needs convering too. But SVE is no yet supported in AOT
    • Do the SVE registers need propagating anywhere else?
  • Is there a testsuite for this?

@a74nh
a74nh marked this pull request as ready for review June 21, 2024 13:22
@a74nh

Copy link
Copy Markdown
ContributorAuthor

Build failures on Windows, but I expected that as that all still needs doing. Marking as ready as I could do with comments, especially on the Windows side.

@dotnet/arm64-contrib @kunalspathak@tannergooding

@kunalspathakkunalspathak added the arm-sve Work related to arm64 SVE/SVE2 support label Jun 21, 2024
@kunalspathak

Copy link
Copy Markdown
Contributor

@JasonLinMS

Comment threadsrc/coreclr/debug/inc/dbgtargetcontext.h Outdated
Comment threadsrc/coreclr/pal/inc/pal.h Outdated
Comment threadsrc/coreclr/pal/src/arch/arm64/context2.S Outdated
}
}

if (sve)

@janvorlijanvorliJun 27, 2024

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.

Similar to x64, we should copy the state only if the contextFlags has the CONTEXT_XSTATE flag set. The passed in contextFlags list parts of the state that are valid that the caller is interested in.

It seems it would make sense to move this to the end of the function next to where we extract xstate for amd64 and put it under the same if ((contextFlags & CONTEXT_XSTATE) == CONTEXT_XSTATE).

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Similar to x64, we should copy the state only if the contextFlags has the CONTEXT_XSTATE flag set.

There is one remaining test failure I've just debugged to being due to this. Will fix it up.

sub x0, x0, CONTEXT_FLOAT_CONTROL_OFFSET + CONTEXT_NEON_OFFSET

LOCAL_LABEL(Done_CONTEXT_FLOATING_POINT):
ldr x1, [x0, CONTEXT_XSTATEFEATURESMASK_OFFSET]

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.

It should check the CONTEXT_XSTATE in CONTEXT_ContextFlags first and check the features mask only if the CONTEXT_XSTATE is set.

// since we potentially clobber x0 below, we'll bank it in x16
mov x16, x0

ldr w17, [x16, CONTEXT_XSTATEFEATURESMASK_OFFSET]

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.

It should check the CONTEXT_XSTATE in CONTEXT_ContextFlags first and check the features mask only if the CONTEXT_XSTATE is set.

#endif // XSTATE_SUPPORTED || (HOST_AMD64 && HAVE_MACH_EXCEPTIONS)

#if defined(HOST_64BIT) && defined(HOST_ARM64) && !defined(TARGET_FREEBSD) && !defined(TARGET_OSX)
#if !defined(SVE_MAGIC)

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.

Is this define not present when building in our CI?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Is this define not present when building in our CI?

Yes, they are missing in the CI. If I remove any of them the build falls over. I think this is when cross compiling. Eithe way, it must be an old Linux being used because these defines have been present in Linux since about 2017.

@janvorli

Copy link
Copy Markdown
Member

Besides the few comments, it looks good.

@a74nh

Copy link
Copy Markdown
ContributorAuthor

Fixed up so that XSTATE is set and checked as suggested.
Everything in run.sh passes and I can see state getting copied when debugging around signals.

This PR enables -DXSTATE_SUPPORTED on Arm64. Am I correct in thinking that on AMD64 Windows this flag is also used in certain scenarios to ensure the xstate data is block copied? If that is the case, then on Arm64 Windows this support still needs adding - probably by just enabling some AMD64 defines for ARM64. However, I've not go a windows setup and so don't want to blindly do anything here and recommend someone checks windows this after this PR is merged.

@a74nh

Copy link
Copy Markdown
ContributorAuthor

Running all priority 1 tests in checked on SVE Linux....

Time [secs] | Total | Passed | Failed | Skipped | Assembly Execution Summary
============================================================================
30.836 | 131 | 131 | 0 | 0 | JIT.Regression.Regression_4
13.873 | 345 | 342 | 0 | 3 | JIT.Regression.Regression_3
13.446 | 53 | 53 | 0 | 0 | CoreMangLib.CoreMangLib
11.249 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests900-999
13.538 | 76 | 76 | 0 | 0 | GC.API.XUnitWrapper.dll
1.225 | 3 | 3 | 0 | 0 | GC.Coverage.XUnitWrapper.dll
183.980 | 42 | 42 | 0 | 0 | GC.Features.XUnitWrapper.dll
3.100 | 6 | 6 | 0 | 0 | GC.LargeMemory.XUnitWrapper.dll
4.731 | 12 | 12 | 0 | 0 | GC.Regressions.XUnitWrapper.dll
22.314 | 481 | 481 | 0 | 0 | GC.Scenarios.XUnitWrapper.dll
0.039 | 1 | 1 | 0 | 0 | GC.Stress.XUnitWrapper.dll
0.534 | 1 | 1 | 0 | 0 | ilasm.PortablePdb.XUnitWrapper.dll
0.619 | 1 | 1 | 0 | 0 | ilasm.System.XUnitWrapper.dll
2.668 | 1 | 1 | 0 | 0 | ilverify.XUnitWrapper.dll
0.537 | 2 | 2 | 0 | 0 | profiler.assembly.XUnitWrapper.dll
1.236 | 2 | 2 | 0 | 0 | profiler.elt.XUnitWrapper.dll
0.793 | 3 | 3 | 0 | 0 | profiler.eventpipe.XUnitWrapper.dll
0.983 | 4 | 4 | 0 | 0 | profiler.gc.XUnitWrapper.dll
0.557 | 1 | 1 | 0 | 0 | profiler.handles.XUnitWrapper.dll
0.038 | 1 | 1 | 0 | 0 | profiler.multiple.XUnitWrapper.dll
0.037 | 1 | 1 | 0 | 0 | profiler.rejit.XUnitWrapper.dll
1.360 | 1 | 1 | 0 | 0 | profiler.transitions.XUnitWrapper.dll
4.133 | 5 | 5 | 0 | 0 | profiler.unittest.XUnitWrapper.dll
0.117 | 1 | 0 | 0 | 1 | JIT.jit64.jit64_2
5.451 | 116 | 116 | 0 | 0 | JIT.SIMD.JIT.SIMD
6.433 | 101 | 101 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests1400-1599
4.025 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests200-299
10.097 | 230 | 227 | 1 | 2 | JIT.Directed.Directed_3
19.526 | 214 | 214 | 0 | 0 | JIT.Directed.Directed_1
5.211 | 216 | 216 | 0 | 0 | JIT.Generics.JIT.Generics
8.080 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests1200-1299
12.593 | 16 | 16 | 0 | 0 | reflection.reflection
138.821 | 100 | 100 | 0 | 0 | JIT.Performance.JIT.performance
172.627 | 11 | 11 | 0 | 0 | JIT.JIT_others
2.365 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests0-99
1.128 | 2 | 1 | 0 | 1 | Exceptions.Exceptions
60.075 | 88 | 88 | 0 | 0 | baseservices.threading.threading_group2
2.885 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests500-599
158.641 | 322 | 321 | 0 | 1 | Loader.Loader
17.855 | 226 | 207 | 0 | 19 | Interop.Interop
5.244 | 437 | 433 | 0 | 4 | JIT.Regression.Regression_6
8.702 | 641 | 641 | 0 | 0 | JIT.CodeGenBringUpTests.JIT.CodeGenBringUpTests
6.596 | 16 | 16 | 0 | 0 | JIT.JIT_r
23.990 | 482 | 480 | 0 | 2 | JIT.Regression.Regression_1
8.302 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests700-799
0.522 | 3 | 3 | 0 | 0 | JIT.JIT_do
9.039 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests1100-1199
2.658 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests400-499
48.146 | 112 | 112 | 0 | 0 | JIT.jit64.jit64_1
84.672 | 1 | 1 | 0 | 0 | readytorun.coreroot_determinism.readytorun_coreroot_determinism
13.396 | 215 | 215 | 0 | 0 | Loader.classloader.generics.LoaderClassloaderGenerics
2.474 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests100-199
43.988 | 2551 | 2551 | 0 | 0 | JIT.HardwareIntrinsics.HardwareIntrinsics_General_ro
9.626 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests1300-1399
76.360 | 75 | 75 | 0 | 0 | Regressions.Regressions
5.244 | 211 | 210 | 0 | 1 | JIT.Methodical.Methodical_r2
5.458 | 85 | 85 | 0 | 0 | JIT.Methodical.Methodical_ro
9.593 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests800-899
75.522 | 20 | 18 | 0 | 2 | readytorun.readytorun
12.881 | 279 | 279 | 0 | 0 | JIT.Methodical.Methodical_r1
3.120 | 343 | 343 | 0 | 0 | JIT.jit64.jit64_4
1.532 | 47 | 47 | 0 | 0 | JIT.Regression.Regression_5
41.352 | 144 | 142 | 0 | 2 | baseservices.exceptions.baseservices-exceptions
9.289 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests1000-1099
18.946 | 67 | 67 | 0 | 0 | Loader.classloader.regressions.LoaderClassloaderRegressions
83.636 | 355 | 353 | 0 | 2 | JIT.opt.JIT.opt
5.979 | 85 | 85 | 0 | 0 | JIT.Methodical.Methodical_do
4.367 | 35 | 33 | 0 | 2 | tracing.tracing
37.561 | 485 | 484 | 0 | 1 | JIT.Regression.Regression_2
13.844 | 276 | 276 | 0 | 0 | JIT.Methodical.Methodical_d1
0.467 | 2 | 2 | 0 | 0 | JIT.JIT_d
92.261 | 143 | 139 | 0 | 4 | JIT.jit64.jit64_3
6.514 | 16 | 16 | 0 | 0 | JIT.JIT_ro
50.519 | 39 | 35 | 0 | 4 | baseservices.baseservices
7.336 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests600-699
5.981 | 208 | 207 | 0 | 1 | JIT.Methodical.Methodical_d2
35.809 | 231 | 226 | 0 | 5 | JIT.jit64.jit64_5
49.200 | 2584 | 2584 | 0 | 0 | JIT.HardwareIntrinsics.HardwareIntrinsics_General_r
1.555 | 55 | 54 | 0 | 1 | JIT.Methodical.Methodical_others
3.838 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests300-399
0.088 | 0 | 0 | 0 | 0 | managed.Managed
54.354 | 203 | 199 | 0 | 4 | JIT.Directed.Directed_2
2.741 | 405 | 405 | 0 | 0 | JIT.IL_Conformance.IL_Conformance
77.532 | 82 | 81 | 0 | 1 | baseservices.threading.threading_group1
----------------------------------------------------------------------------
1997.991 | 15149 | 15085 | 1 | 63 | (total)

That single failure I get on latest head, so I'm not worried about it.

Comment threadsrc/coreclr/pal/src/arch/arm64/context2.S
@jkotas

Copy link
Copy Markdown
Member

I see a lot of TODOs about SVE size being hardcoded to 128 bit.

What is going to be the experience when somebody runs .NET 9 binary on a machine with 256 bit SVE? It is important that it just works, without crashing, buffer overruns, etc.

@a74nh

Copy link
Copy Markdown
ContributorAuthor

I see a lot of TODOs about SVE size being hardcoded to 128 bit.

What is going to be the experience when somebody runs .NET 9 binary on a machine with 256 bit SVE? It is important that it just works, without crashing, buffer overruns, etc.

Running the entire testsuite on 256bit, all the tests pass with and without my latest fix. That's because there is no SVE state in the kernel, so that structure that comes back from the OS has no SVE state (sve.size is 16, it's just the header with no data).

Comment threadsrc/coreclr/pal/src/arch/arm64/asmconstants.h

@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.

Thanks @a74nh for your contribution. LGTM.

@kunalspathak

Copy link
Copy Markdown
Contributor

/ba-g failure is #103550

@kunalspathak
kunalspathak merged commit 9528c15 into dotnet:mainJun 29, 2024
akoeplinger added a commit to akoeplinger/runtime that referenced this pull request Jul 8, 2024
It got broken by dotnet#103801 due to a host vs. target arch typo.
This showed up in the VMR since we use arm64 macOS build agents there.
akoeplinger added a commit to akoeplinger/runtime that referenced this pull request Jul 8, 2024
It got uncovered by dotnet#103801.
This showed up in the VMR since we use arm64 macOS build agents there.
akoeplinger added a commit that referenced this pull request Jul 8, 2024
It got uncovered by #103801.
This showed up in the VMR since we use arm64 macOS build agents there.
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jul 29, 2024
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-PAL-coreclronly for closed issuesarm-sveWork related to arm64 SVE/SVE2 supportcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@a74nh@kunalspathak@janvorli@jkotas@JasonLinMS
, '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

ARM64-SVE: Add SVE registers to pal context - #103801

Merged
kunalspathak merged 29 commits into
dotnet:mainfrom
a74nh:sve_state_github
Jun 29, 2024
Merged

ARM64-SVE: Add SVE registers to pal context#103801
kunalspathak merged 29 commits into
dotnet:mainfrom
a74nh:sve_state_github

Conversation

@a74nh

@a74nha74nh commented Jun 21, 2024

Copy link
Copy Markdown
Contributor

Adds Linux support for SVE state on signals.

Testing:
I forced a sigill (by making one of the hwintrinsic API calls generate a bad instruction). I checked the SVE registers when the signal occurred. I stepped through and made sure the lpContext is correctly filled.

@ghostghost added the area-PAL-coreclr only for closed issues label Jun 21, 2024
@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Jun 21, 2024
Comment threadsrc/coreclr/pal/inc/pal.h Outdated
//
// Sve Registers
//
//TODO-SVE: How does this structure handle variable sized Z/P/FFR registers?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

AIUI, this should match the same structure in Windows. I don't have the any documentation, so I've made a guess at what the fields should be for SVE, and I expect that it's wrong
For convenience I've only used a vector length 128bits. I'd be surprised if windows supports a full 2048bit vector length without doing anything special.
(Offsets below marked with a ? I'll fix once the structure is correct)

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.

Windows in general don't store extended context parts in the CONTEXT data structure itself. There is a flag CONTEXT_XSTATE that indicates presence of extra data attached to the CONTEXT. There are APIs InitializeContext and InitializeContext2 that allows setting up a context for the extended state. It can be also used to get the size of memory needed for the extended context. The InitializeContext2 is a new one that allows to select only a subset of the extended state using the XStateCompactionMask argument.

We have done this differently for AVX512 for the sake of simplicity - we have included the extra registers in the CONTEXT structure itself. I think it would be better to move that to the way Windows handle that so that we don't waste time initializing and copying extra fields at places where we don't care about the extended state or when the current CPU doesn't support them. That would also allow to size the storage for the Z/P registers dynamically based on the current CPU.
Having said that though, for this PR, we can follow the suite and do the same thing we did for intel avx512 and migrate both to the better model later. Based on what @kunalspathak told me, starting with 128 bits of space for the registers should be sufficient for now.

I would add them to the very end of the CONTEXT after the debug registers so that the layout of the part that's common with Windows is the same.

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.

Yep, for the OS, extended context like SVE and AVX etc are stored in a variable-sized buffer separate from the CONTEXT. The CONTEXT_EX structure immediately follows the CONTEXT structure, and contains pointers to the variable-sized XSTATE buffer. On x64, the XSTATE buffer is in the exact format that is supported by the hardware via the XSAVE and XRSTOR instructions. On ARM64, there are no XSAVE/XRSTOR instructions, but the XSTATE buffer is laid out in a similar fashion to x64 (including Header->Mask, Header->CompationMask etc), to allow for max code sharing with x64.

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.

The OS kernel does support all SVE vector lengths, up to 2048-bit SVE, though there is the caveat that HyperV only supports 128-bit SVE. So, when running on hardware that supports SVE larger than 128-bits, if HyperV is enabled you'll only see 128-bit SVE, but if HyperV is off then you'll be able to take advantage of the full SVE width supported by the CPU. And to my understanding, there is likely hardware in the future that supports larger SVE lengths than 128-bit, though I don't know any specific on timelines.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks for the comments. Updated with the following:

  • Added context2.S changes
  • Removed store/restore of Z registers (as we only support 128bits for now, which fully overlap the V registers)
  • Added a XStateFeaturesMask to the Arm64 context so that we can tell whether to use SVE or not.

I'm currently unsure where else SVE state might need saving/restoring

@a74nh

Copy link
Copy Markdown
ContributorAuthor

Things I'm unsure about:

  • What the LPCONTEXT should look like
  • If there are extra areas in coreclr that need covering
    • I think AOT needs convering too. But SVE is no yet supported in AOT
    • Do the SVE registers need propagating anywhere else?
  • Is there a testsuite for this?

@a74nh
a74nh marked this pull request as ready for review June 21, 2024 13:22
@a74nh

Copy link
Copy Markdown
ContributorAuthor

Build failures on Windows, but I expected that as that all still needs doing. Marking as ready as I could do with comments, especially on the Windows side.

@dotnet/arm64-contrib @kunalspathak@tannergooding

@kunalspathakkunalspathak added the arm-sve Work related to arm64 SVE/SVE2 support label Jun 21, 2024
@kunalspathak

Copy link
Copy Markdown
Contributor

@JasonLinMS

Comment threadsrc/coreclr/debug/inc/dbgtargetcontext.h Outdated
Comment threadsrc/coreclr/pal/inc/pal.h Outdated
Comment threadsrc/coreclr/pal/src/arch/arm64/context2.S Outdated
}
}

if (sve)

@janvorlijanvorliJun 27, 2024

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.

Similar to x64, we should copy the state only if the contextFlags has the CONTEXT_XSTATE flag set. The passed in contextFlags list parts of the state that are valid that the caller is interested in.

It seems it would make sense to move this to the end of the function next to where we extract xstate for amd64 and put it under the same if ((contextFlags & CONTEXT_XSTATE) == CONTEXT_XSTATE).

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Similar to x64, we should copy the state only if the contextFlags has the CONTEXT_XSTATE flag set.

There is one remaining test failure I've just debugged to being due to this. Will fix it up.

sub x0, x0, CONTEXT_FLOAT_CONTROL_OFFSET + CONTEXT_NEON_OFFSET

LOCAL_LABEL(Done_CONTEXT_FLOATING_POINT):
ldr x1, [x0, CONTEXT_XSTATEFEATURESMASK_OFFSET]

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.

It should check the CONTEXT_XSTATE in CONTEXT_ContextFlags first and check the features mask only if the CONTEXT_XSTATE is set.

// since we potentially clobber x0 below, we'll bank it in x16
mov x16, x0

ldr w17, [x16, CONTEXT_XSTATEFEATURESMASK_OFFSET]

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.

It should check the CONTEXT_XSTATE in CONTEXT_ContextFlags first and check the features mask only if the CONTEXT_XSTATE is set.

#endif // XSTATE_SUPPORTED || (HOST_AMD64 && HAVE_MACH_EXCEPTIONS)

#if defined(HOST_64BIT) && defined(HOST_ARM64) && !defined(TARGET_FREEBSD) && !defined(TARGET_OSX)
#if !defined(SVE_MAGIC)

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.

Is this define not present when building in our CI?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Is this define not present when building in our CI?

Yes, they are missing in the CI. If I remove any of them the build falls over. I think this is when cross compiling. Eithe way, it must be an old Linux being used because these defines have been present in Linux since about 2017.

@janvorli

Copy link
Copy Markdown
Member

Besides the few comments, it looks good.

@a74nh

Copy link
Copy Markdown
ContributorAuthor

Fixed up so that XSTATE is set and checked as suggested.
Everything in run.sh passes and I can see state getting copied when debugging around signals.

This PR enables -DXSTATE_SUPPORTED on Arm64. Am I correct in thinking that on AMD64 Windows this flag is also used in certain scenarios to ensure the xstate data is block copied? If that is the case, then on Arm64 Windows this support still needs adding - probably by just enabling some AMD64 defines for ARM64. However, I've not go a windows setup and so don't want to blindly do anything here and recommend someone checks windows this after this PR is merged.

@a74nh

Copy link
Copy Markdown
ContributorAuthor

Running all priority 1 tests in checked on SVE Linux....

Time [secs] | Total | Passed | Failed | Skipped | Assembly Execution Summary
============================================================================
30.836 | 131 | 131 | 0 | 0 | JIT.Regression.Regression_4
13.873 | 345 | 342 | 0 | 3 | JIT.Regression.Regression_3
13.446 | 53 | 53 | 0 | 0 | CoreMangLib.CoreMangLib
11.249 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests900-999
13.538 | 76 | 76 | 0 | 0 | GC.API.XUnitWrapper.dll
1.225 | 3 | 3 | 0 | 0 | GC.Coverage.XUnitWrapper.dll
183.980 | 42 | 42 | 0 | 0 | GC.Features.XUnitWrapper.dll
3.100 | 6 | 6 | 0 | 0 | GC.LargeMemory.XUnitWrapper.dll
4.731 | 12 | 12 | 0 | 0 | GC.Regressions.XUnitWrapper.dll
22.314 | 481 | 481 | 0 | 0 | GC.Scenarios.XUnitWrapper.dll
0.039 | 1 | 1 | 0 | 0 | GC.Stress.XUnitWrapper.dll
0.534 | 1 | 1 | 0 | 0 | ilasm.PortablePdb.XUnitWrapper.dll
0.619 | 1 | 1 | 0 | 0 | ilasm.System.XUnitWrapper.dll
2.668 | 1 | 1 | 0 | 0 | ilverify.XUnitWrapper.dll
0.537 | 2 | 2 | 0 | 0 | profiler.assembly.XUnitWrapper.dll
1.236 | 2 | 2 | 0 | 0 | profiler.elt.XUnitWrapper.dll
0.793 | 3 | 3 | 0 | 0 | profiler.eventpipe.XUnitWrapper.dll
0.983 | 4 | 4 | 0 | 0 | profiler.gc.XUnitWrapper.dll
0.557 | 1 | 1 | 0 | 0 | profiler.handles.XUnitWrapper.dll
0.038 | 1 | 1 | 0 | 0 | profiler.multiple.XUnitWrapper.dll
0.037 | 1 | 1 | 0 | 0 | profiler.rejit.XUnitWrapper.dll
1.360 | 1 | 1 | 0 | 0 | profiler.transitions.XUnitWrapper.dll
4.133 | 5 | 5 | 0 | 0 | profiler.unittest.XUnitWrapper.dll
0.117 | 1 | 0 | 0 | 1 | JIT.jit64.jit64_2
5.451 | 116 | 116 | 0 | 0 | JIT.SIMD.JIT.SIMD
6.433 | 101 | 101 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests1400-1599
4.025 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests200-299
10.097 | 230 | 227 | 1 | 2 | JIT.Directed.Directed_3
19.526 | 214 | 214 | 0 | 0 | JIT.Directed.Directed_1
5.211 | 216 | 216 | 0 | 0 | JIT.Generics.JIT.Generics
8.080 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests1200-1299
12.593 | 16 | 16 | 0 | 0 | reflection.reflection
138.821 | 100 | 100 | 0 | 0 | JIT.Performance.JIT.performance
172.627 | 11 | 11 | 0 | 0 | JIT.JIT_others
2.365 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests0-99
1.128 | 2 | 1 | 0 | 1 | Exceptions.Exceptions
60.075 | 88 | 88 | 0 | 0 | baseservices.threading.threading_group2
2.885 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests500-599
158.641 | 322 | 321 | 0 | 1 | Loader.Loader
17.855 | 226 | 207 | 0 | 19 | Interop.Interop
5.244 | 437 | 433 | 0 | 4 | JIT.Regression.Regression_6
8.702 | 641 | 641 | 0 | 0 | JIT.CodeGenBringUpTests.JIT.CodeGenBringUpTests
6.596 | 16 | 16 | 0 | 0 | JIT.JIT_r
23.990 | 482 | 480 | 0 | 2 | JIT.Regression.Regression_1
8.302 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests700-799
0.522 | 3 | 3 | 0 | 0 | JIT.JIT_do
9.039 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests1100-1199
2.658 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests400-499
48.146 | 112 | 112 | 0 | 0 | JIT.jit64.jit64_1
84.672 | 1 | 1 | 0 | 0 | readytorun.coreroot_determinism.readytorun_coreroot_determinism
13.396 | 215 | 215 | 0 | 0 | Loader.classloader.generics.LoaderClassloaderGenerics
2.474 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests100-199
43.988 | 2551 | 2551 | 0 | 0 | JIT.HardwareIntrinsics.HardwareIntrinsics_General_ro
9.626 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests1300-1399
76.360 | 75 | 75 | 0 | 0 | Regressions.Regressions
5.244 | 211 | 210 | 0 | 1 | JIT.Methodical.Methodical_r2
5.458 | 85 | 85 | 0 | 0 | JIT.Methodical.Methodical_ro
9.593 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests800-899
75.522 | 20 | 18 | 0 | 2 | readytorun.readytorun
12.881 | 279 | 279 | 0 | 0 | JIT.Methodical.Methodical_r1
3.120 | 343 | 343 | 0 | 0 | JIT.jit64.jit64_4
1.532 | 47 | 47 | 0 | 0 | JIT.Regression.Regression_5
41.352 | 144 | 142 | 0 | 2 | baseservices.exceptions.baseservices-exceptions
9.289 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests1000-1099
18.946 | 67 | 67 | 0 | 0 | Loader.classloader.regressions.LoaderClassloaderRegressions
83.636 | 355 | 353 | 0 | 2 | JIT.opt.JIT.opt
5.979 | 85 | 85 | 0 | 0 | JIT.Methodical.Methodical_do
4.367 | 35 | 33 | 0 | 2 | tracing.tracing
37.561 | 485 | 484 | 0 | 1 | JIT.Regression.Regression_2
13.844 | 276 | 276 | 0 | 0 | JIT.Methodical.Methodical_d1
0.467 | 2 | 2 | 0 | 0 | JIT.JIT_d
92.261 | 143 | 139 | 0 | 4 | JIT.jit64.jit64_3
6.514 | 16 | 16 | 0 | 0 | JIT.JIT_ro
50.519 | 39 | 35 | 0 | 4 | baseservices.baseservices
7.336 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests600-699
5.981 | 208 | 207 | 0 | 1 | JIT.Methodical.Methodical_d2
35.809 | 231 | 226 | 0 | 5 | JIT.jit64.jit64_5
49.200 | 2584 | 2584 | 0 | 0 | JIT.HardwareIntrinsics.HardwareIntrinsics_General_r
1.555 | 55 | 54 | 0 | 1 | JIT.Methodical.Methodical_others
3.838 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests300-399
0.088 | 0 | 0 | 0 | 0 | managed.Managed
54.354 | 203 | 199 | 0 | 4 | JIT.Directed.Directed_2
2.741 | 405 | 405 | 0 | 0 | JIT.IL_Conformance.IL_Conformance
77.532 | 82 | 81 | 0 | 1 | baseservices.threading.threading_group1
----------------------------------------------------------------------------
1997.991 | 15149 | 15085 | 1 | 63 | (total)

That single failure I get on latest head, so I'm not worried about it.

Comment threadsrc/coreclr/pal/src/arch/arm64/context2.S
@jkotas

Copy link
Copy Markdown
Member

I see a lot of TODOs about SVE size being hardcoded to 128 bit.

What is going to be the experience when somebody runs .NET 9 binary on a machine with 256 bit SVE? It is important that it just works, without crashing, buffer overruns, etc.

@a74nh

Copy link
Copy Markdown
ContributorAuthor

I see a lot of TODOs about SVE size being hardcoded to 128 bit.

What is going to be the experience when somebody runs .NET 9 binary on a machine with 256 bit SVE? It is important that it just works, without crashing, buffer overruns, etc.

Running the entire testsuite on 256bit, all the tests pass with and without my latest fix. That's because there is no SVE state in the kernel, so that structure that comes back from the OS has no SVE state (sve.size is 16, it's just the header with no data).

Comment threadsrc/coreclr/pal/src/arch/arm64/asmconstants.h

@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.

Thanks @a74nh for your contribution. LGTM.

@kunalspathak

Copy link
Copy Markdown
Contributor

/ba-g failure is #103550

@kunalspathak
kunalspathak merged commit 9528c15 into dotnet:mainJun 29, 2024
akoeplinger added a commit to akoeplinger/runtime that referenced this pull request Jul 8, 2024
It got broken by dotnet#103801 due to a host vs. target arch typo.
This showed up in the VMR since we use arm64 macOS build agents there.
akoeplinger added a commit to akoeplinger/runtime that referenced this pull request Jul 8, 2024
It got uncovered by dotnet#103801.
This showed up in the VMR since we use arm64 macOS build agents there.
akoeplinger added a commit that referenced this pull request Jul 8, 2024
It got uncovered by #103801.
This showed up in the VMR since we use arm64 macOS build agents there.
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jul 29, 2024
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-PAL-coreclronly for closed issuesarm-sveWork related to arm64 SVE/SVE2 supportcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@a74nh@kunalspathak@janvorli@jkotas@JasonLinMS
, '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

ARM64-SVE: Add SVE registers to pal context - #103801

Merged
kunalspathak merged 29 commits into
dotnet:mainfrom
a74nh:sve_state_github
Jun 29, 2024
Merged

ARM64-SVE: Add SVE registers to pal context#103801
kunalspathak merged 29 commits into
dotnet:mainfrom
a74nh:sve_state_github

Conversation

@a74nh

@a74nha74nh commented Jun 21, 2024

Copy link
Copy Markdown
Contributor

Adds Linux support for SVE state on signals.

Testing:
I forced a sigill (by making one of the hwintrinsic API calls generate a bad instruction). I checked the SVE registers when the signal occurred. I stepped through and made sure the lpContext is correctly filled.

@ghostghost added the area-PAL-coreclr only for closed issues label Jun 21, 2024
@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Jun 21, 2024
Comment threadsrc/coreclr/pal/inc/pal.h Outdated
//
// Sve Registers
//
//TODO-SVE: How does this structure handle variable sized Z/P/FFR registers?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

AIUI, this should match the same structure in Windows. I don't have the any documentation, so I've made a guess at what the fields should be for SVE, and I expect that it's wrong
For convenience I've only used a vector length 128bits. I'd be surprised if windows supports a full 2048bit vector length without doing anything special.
(Offsets below marked with a ? I'll fix once the structure is correct)

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.

Windows in general don't store extended context parts in the CONTEXT data structure itself. There is a flag CONTEXT_XSTATE that indicates presence of extra data attached to the CONTEXT. There are APIs InitializeContext and InitializeContext2 that allows setting up a context for the extended state. It can be also used to get the size of memory needed for the extended context. The InitializeContext2 is a new one that allows to select only a subset of the extended state using the XStateCompactionMask argument.

We have done this differently for AVX512 for the sake of simplicity - we have included the extra registers in the CONTEXT structure itself. I think it would be better to move that to the way Windows handle that so that we don't waste time initializing and copying extra fields at places where we don't care about the extended state or when the current CPU doesn't support them. That would also allow to size the storage for the Z/P registers dynamically based on the current CPU.
Having said that though, for this PR, we can follow the suite and do the same thing we did for intel avx512 and migrate both to the better model later. Based on what @kunalspathak told me, starting with 128 bits of space for the registers should be sufficient for now.

I would add them to the very end of the CONTEXT after the debug registers so that the layout of the part that's common with Windows is the same.

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.

Yep, for the OS, extended context like SVE and AVX etc are stored in a variable-sized buffer separate from the CONTEXT. The CONTEXT_EX structure immediately follows the CONTEXT structure, and contains pointers to the variable-sized XSTATE buffer. On x64, the XSTATE buffer is in the exact format that is supported by the hardware via the XSAVE and XRSTOR instructions. On ARM64, there are no XSAVE/XRSTOR instructions, but the XSTATE buffer is laid out in a similar fashion to x64 (including Header->Mask, Header->CompationMask etc), to allow for max code sharing with x64.

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.

The OS kernel does support all SVE vector lengths, up to 2048-bit SVE, though there is the caveat that HyperV only supports 128-bit SVE. So, when running on hardware that supports SVE larger than 128-bits, if HyperV is enabled you'll only see 128-bit SVE, but if HyperV is off then you'll be able to take advantage of the full SVE width supported by the CPU. And to my understanding, there is likely hardware in the future that supports larger SVE lengths than 128-bit, though I don't know any specific on timelines.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks for the comments. Updated with the following:

  • Added context2.S changes
  • Removed store/restore of Z registers (as we only support 128bits for now, which fully overlap the V registers)
  • Added a XStateFeaturesMask to the Arm64 context so that we can tell whether to use SVE or not.

I'm currently unsure where else SVE state might need saving/restoring

@a74nh

Copy link
Copy Markdown
ContributorAuthor

Things I'm unsure about:

  • What the LPCONTEXT should look like
  • If there are extra areas in coreclr that need covering
    • I think AOT needs convering too. But SVE is no yet supported in AOT
    • Do the SVE registers need propagating anywhere else?
  • Is there a testsuite for this?

@a74nh
a74nh marked this pull request as ready for review June 21, 2024 13:22
@a74nh

Copy link
Copy Markdown
ContributorAuthor

Build failures on Windows, but I expected that as that all still needs doing. Marking as ready as I could do with comments, especially on the Windows side.

@dotnet/arm64-contrib @kunalspathak@tannergooding

@kunalspathakkunalspathak added the arm-sve Work related to arm64 SVE/SVE2 support label Jun 21, 2024
@kunalspathak

Copy link
Copy Markdown
Contributor

@JasonLinMS

Comment threadsrc/coreclr/debug/inc/dbgtargetcontext.h Outdated
Comment threadsrc/coreclr/pal/inc/pal.h Outdated
Comment threadsrc/coreclr/pal/src/arch/arm64/context2.S Outdated
}
}

if (sve)

@janvorlijanvorliJun 27, 2024

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.

Similar to x64, we should copy the state only if the contextFlags has the CONTEXT_XSTATE flag set. The passed in contextFlags list parts of the state that are valid that the caller is interested in.

It seems it would make sense to move this to the end of the function next to where we extract xstate for amd64 and put it under the same if ((contextFlags & CONTEXT_XSTATE) == CONTEXT_XSTATE).

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Similar to x64, we should copy the state only if the contextFlags has the CONTEXT_XSTATE flag set.

There is one remaining test failure I've just debugged to being due to this. Will fix it up.

sub x0, x0, CONTEXT_FLOAT_CONTROL_OFFSET + CONTEXT_NEON_OFFSET

LOCAL_LABEL(Done_CONTEXT_FLOATING_POINT):
ldr x1, [x0, CONTEXT_XSTATEFEATURESMASK_OFFSET]

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.

It should check the CONTEXT_XSTATE in CONTEXT_ContextFlags first and check the features mask only if the CONTEXT_XSTATE is set.

// since we potentially clobber x0 below, we'll bank it in x16
mov x16, x0

ldr w17, [x16, CONTEXT_XSTATEFEATURESMASK_OFFSET]

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.

It should check the CONTEXT_XSTATE in CONTEXT_ContextFlags first and check the features mask only if the CONTEXT_XSTATE is set.

#endif // XSTATE_SUPPORTED || (HOST_AMD64 && HAVE_MACH_EXCEPTIONS)

#if defined(HOST_64BIT) && defined(HOST_ARM64) && !defined(TARGET_FREEBSD) && !defined(TARGET_OSX)
#if !defined(SVE_MAGIC)

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.

Is this define not present when building in our CI?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Is this define not present when building in our CI?

Yes, they are missing in the CI. If I remove any of them the build falls over. I think this is when cross compiling. Eithe way, it must be an old Linux being used because these defines have been present in Linux since about 2017.

@janvorli

Copy link
Copy Markdown
Member

Besides the few comments, it looks good.

@a74nh

Copy link
Copy Markdown
ContributorAuthor

Fixed up so that XSTATE is set and checked as suggested.
Everything in run.sh passes and I can see state getting copied when debugging around signals.

This PR enables -DXSTATE_SUPPORTED on Arm64. Am I correct in thinking that on AMD64 Windows this flag is also used in certain scenarios to ensure the xstate data is block copied? If that is the case, then on Arm64 Windows this support still needs adding - probably by just enabling some AMD64 defines for ARM64. However, I've not go a windows setup and so don't want to blindly do anything here and recommend someone checks windows this after this PR is merged.

@a74nh

Copy link
Copy Markdown
ContributorAuthor

Running all priority 1 tests in checked on SVE Linux....

Time [secs] | Total | Passed | Failed | Skipped | Assembly Execution Summary
============================================================================
30.836 | 131 | 131 | 0 | 0 | JIT.Regression.Regression_4
13.873 | 345 | 342 | 0 | 3 | JIT.Regression.Regression_3
13.446 | 53 | 53 | 0 | 0 | CoreMangLib.CoreMangLib
11.249 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests900-999
13.538 | 76 | 76 | 0 | 0 | GC.API.XUnitWrapper.dll
1.225 | 3 | 3 | 0 | 0 | GC.Coverage.XUnitWrapper.dll
183.980 | 42 | 42 | 0 | 0 | GC.Features.XUnitWrapper.dll
3.100 | 6 | 6 | 0 | 0 | GC.LargeMemory.XUnitWrapper.dll
4.731 | 12 | 12 | 0 | 0 | GC.Regressions.XUnitWrapper.dll
22.314 | 481 | 481 | 0 | 0 | GC.Scenarios.XUnitWrapper.dll
0.039 | 1 | 1 | 0 | 0 | GC.Stress.XUnitWrapper.dll
0.534 | 1 | 1 | 0 | 0 | ilasm.PortablePdb.XUnitWrapper.dll
0.619 | 1 | 1 | 0 | 0 | ilasm.System.XUnitWrapper.dll
2.668 | 1 | 1 | 0 | 0 | ilverify.XUnitWrapper.dll
0.537 | 2 | 2 | 0 | 0 | profiler.assembly.XUnitWrapper.dll
1.236 | 2 | 2 | 0 | 0 | profiler.elt.XUnitWrapper.dll
0.793 | 3 | 3 | 0 | 0 | profiler.eventpipe.XUnitWrapper.dll
0.983 | 4 | 4 | 0 | 0 | profiler.gc.XUnitWrapper.dll
0.557 | 1 | 1 | 0 | 0 | profiler.handles.XUnitWrapper.dll
0.038 | 1 | 1 | 0 | 0 | profiler.multiple.XUnitWrapper.dll
0.037 | 1 | 1 | 0 | 0 | profiler.rejit.XUnitWrapper.dll
1.360 | 1 | 1 | 0 | 0 | profiler.transitions.XUnitWrapper.dll
4.133 | 5 | 5 | 0 | 0 | profiler.unittest.XUnitWrapper.dll
0.117 | 1 | 0 | 0 | 1 | JIT.jit64.jit64_2
5.451 | 116 | 116 | 0 | 0 | JIT.SIMD.JIT.SIMD
6.433 | 101 | 101 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests1400-1599
4.025 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests200-299
10.097 | 230 | 227 | 1 | 2 | JIT.Directed.Directed_3
19.526 | 214 | 214 | 0 | 0 | JIT.Directed.Directed_1
5.211 | 216 | 216 | 0 | 0 | JIT.Generics.JIT.Generics
8.080 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests1200-1299
12.593 | 16 | 16 | 0 | 0 | reflection.reflection
138.821 | 100 | 100 | 0 | 0 | JIT.Performance.JIT.performance
172.627 | 11 | 11 | 0 | 0 | JIT.JIT_others
2.365 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests0-99
1.128 | 2 | 1 | 0 | 1 | Exceptions.Exceptions
60.075 | 88 | 88 | 0 | 0 | baseservices.threading.threading_group2
2.885 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests500-599
158.641 | 322 | 321 | 0 | 1 | Loader.Loader
17.855 | 226 | 207 | 0 | 19 | Interop.Interop
5.244 | 437 | 433 | 0 | 4 | JIT.Regression.Regression_6
8.702 | 641 | 641 | 0 | 0 | JIT.CodeGenBringUpTests.JIT.CodeGenBringUpTests
6.596 | 16 | 16 | 0 | 0 | JIT.JIT_r
23.990 | 482 | 480 | 0 | 2 | JIT.Regression.Regression_1
8.302 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests700-799
0.522 | 3 | 3 | 0 | 0 | JIT.JIT_do
9.039 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests1100-1199
2.658 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests400-499
48.146 | 112 | 112 | 0 | 0 | JIT.jit64.jit64_1
84.672 | 1 | 1 | 0 | 0 | readytorun.coreroot_determinism.readytorun_coreroot_determinism
13.396 | 215 | 215 | 0 | 0 | Loader.classloader.generics.LoaderClassloaderGenerics
2.474 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests100-199
43.988 | 2551 | 2551 | 0 | 0 | JIT.HardwareIntrinsics.HardwareIntrinsics_General_ro
9.626 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests1300-1399
76.360 | 75 | 75 | 0 | 0 | Regressions.Regressions
5.244 | 211 | 210 | 0 | 1 | JIT.Methodical.Methodical_r2
5.458 | 85 | 85 | 0 | 0 | JIT.Methodical.Methodical_ro
9.593 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests800-899
75.522 | 20 | 18 | 0 | 2 | readytorun.readytorun
12.881 | 279 | 279 | 0 | 0 | JIT.Methodical.Methodical_r1
3.120 | 343 | 343 | 0 | 0 | JIT.jit64.jit64_4
1.532 | 47 | 47 | 0 | 0 | JIT.Regression.Regression_5
41.352 | 144 | 142 | 0 | 2 | baseservices.exceptions.baseservices-exceptions
9.289 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests1000-1099
18.946 | 67 | 67 | 0 | 0 | Loader.classloader.regressions.LoaderClassloaderRegressions
83.636 | 355 | 353 | 0 | 2 | JIT.opt.JIT.opt
5.979 | 85 | 85 | 0 | 0 | JIT.Methodical.Methodical_do
4.367 | 35 | 33 | 0 | 2 | tracing.tracing
37.561 | 485 | 484 | 0 | 1 | JIT.Regression.Regression_2
13.844 | 276 | 276 | 0 | 0 | JIT.Methodical.Methodical_d1
0.467 | 2 | 2 | 0 | 0 | JIT.JIT_d
92.261 | 143 | 139 | 0 | 4 | JIT.jit64.jit64_3
6.514 | 16 | 16 | 0 | 0 | JIT.JIT_ro
50.519 | 39 | 35 | 0 | 4 | baseservices.baseservices
7.336 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests600-699
5.981 | 208 | 207 | 0 | 1 | JIT.Methodical.Methodical_d2
35.809 | 231 | 226 | 0 | 5 | JIT.jit64.jit64_5
49.200 | 2584 | 2584 | 0 | 0 | JIT.HardwareIntrinsics.HardwareIntrinsics_General_r
1.555 | 55 | 54 | 0 | 1 | JIT.Methodical.Methodical_others
3.838 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests300-399
0.088 | 0 | 0 | 0 | 0 | managed.Managed
54.354 | 203 | 199 | 0 | 4 | JIT.Directed.Directed_2
2.741 | 405 | 405 | 0 | 0 | JIT.IL_Conformance.IL_Conformance
77.532 | 82 | 81 | 0 | 1 | baseservices.threading.threading_group1
----------------------------------------------------------------------------
1997.991 | 15149 | 15085 | 1 | 63 | (total)

That single failure I get on latest head, so I'm not worried about it.

Comment threadsrc/coreclr/pal/src/arch/arm64/context2.S
@jkotas

Copy link
Copy Markdown
Member

I see a lot of TODOs about SVE size being hardcoded to 128 bit.

What is going to be the experience when somebody runs .NET 9 binary on a machine with 256 bit SVE? It is important that it just works, without crashing, buffer overruns, etc.

@a74nh

Copy link
Copy Markdown
ContributorAuthor

I see a lot of TODOs about SVE size being hardcoded to 128 bit.

What is going to be the experience when somebody runs .NET 9 binary on a machine with 256 bit SVE? It is important that it just works, without crashing, buffer overruns, etc.

Running the entire testsuite on 256bit, all the tests pass with and without my latest fix. That's because there is no SVE state in the kernel, so that structure that comes back from the OS has no SVE state (sve.size is 16, it's just the header with no data).

Comment threadsrc/coreclr/pal/src/arch/arm64/asmconstants.h

@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.

Thanks @a74nh for your contribution. LGTM.

@kunalspathak

Copy link
Copy Markdown
Contributor

/ba-g failure is #103550

@kunalspathak
kunalspathak merged commit 9528c15 into dotnet:mainJun 29, 2024
akoeplinger added a commit to akoeplinger/runtime that referenced this pull request Jul 8, 2024
It got broken by dotnet#103801 due to a host vs. target arch typo.
This showed up in the VMR since we use arm64 macOS build agents there.
akoeplinger added a commit to akoeplinger/runtime that referenced this pull request Jul 8, 2024
It got uncovered by dotnet#103801.
This showed up in the VMR since we use arm64 macOS build agents there.
akoeplinger added a commit that referenced this pull request Jul 8, 2024
It got uncovered by #103801.
This showed up in the VMR since we use arm64 macOS build agents there.
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jul 29, 2024
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-PAL-coreclronly for closed issuesarm-sveWork related to arm64 SVE/SVE2 supportcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@a74nh@kunalspathak@janvorli@jkotas@JasonLinMS
, '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

ARM64-SVE: Add SVE registers to pal context - #103801

Merged
kunalspathak merged 29 commits into
dotnet:mainfrom
a74nh:sve_state_github
Jun 29, 2024
Merged

ARM64-SVE: Add SVE registers to pal context#103801
kunalspathak merged 29 commits into
dotnet:mainfrom
a74nh:sve_state_github

Conversation

@a74nh

@a74nha74nh commented Jun 21, 2024

Copy link
Copy Markdown
Contributor

Adds Linux support for SVE state on signals.

Testing:
I forced a sigill (by making one of the hwintrinsic API calls generate a bad instruction). I checked the SVE registers when the signal occurred. I stepped through and made sure the lpContext is correctly filled.

@ghostghost added the area-PAL-coreclr only for closed issues label Jun 21, 2024
@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Jun 21, 2024
Comment threadsrc/coreclr/pal/inc/pal.h Outdated
//
// Sve Registers
//
//TODO-SVE: How does this structure handle variable sized Z/P/FFR registers?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

AIUI, this should match the same structure in Windows. I don't have the any documentation, so I've made a guess at what the fields should be for SVE, and I expect that it's wrong
For convenience I've only used a vector length 128bits. I'd be surprised if windows supports a full 2048bit vector length without doing anything special.
(Offsets below marked with a ? I'll fix once the structure is correct)

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.

Windows in general don't store extended context parts in the CONTEXT data structure itself. There is a flag CONTEXT_XSTATE that indicates presence of extra data attached to the CONTEXT. There are APIs InitializeContext and InitializeContext2 that allows setting up a context for the extended state. It can be also used to get the size of memory needed for the extended context. The InitializeContext2 is a new one that allows to select only a subset of the extended state using the XStateCompactionMask argument.

We have done this differently for AVX512 for the sake of simplicity - we have included the extra registers in the CONTEXT structure itself. I think it would be better to move that to the way Windows handle that so that we don't waste time initializing and copying extra fields at places where we don't care about the extended state or when the current CPU doesn't support them. That would also allow to size the storage for the Z/P registers dynamically based on the current CPU.
Having said that though, for this PR, we can follow the suite and do the same thing we did for intel avx512 and migrate both to the better model later. Based on what @kunalspathak told me, starting with 128 bits of space for the registers should be sufficient for now.

I would add them to the very end of the CONTEXT after the debug registers so that the layout of the part that's common with Windows is the same.

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.

Yep, for the OS, extended context like SVE and AVX etc are stored in a variable-sized buffer separate from the CONTEXT. The CONTEXT_EX structure immediately follows the CONTEXT structure, and contains pointers to the variable-sized XSTATE buffer. On x64, the XSTATE buffer is in the exact format that is supported by the hardware via the XSAVE and XRSTOR instructions. On ARM64, there are no XSAVE/XRSTOR instructions, but the XSTATE buffer is laid out in a similar fashion to x64 (including Header->Mask, Header->CompationMask etc), to allow for max code sharing with x64.

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.

The OS kernel does support all SVE vector lengths, up to 2048-bit SVE, though there is the caveat that HyperV only supports 128-bit SVE. So, when running on hardware that supports SVE larger than 128-bits, if HyperV is enabled you'll only see 128-bit SVE, but if HyperV is off then you'll be able to take advantage of the full SVE width supported by the CPU. And to my understanding, there is likely hardware in the future that supports larger SVE lengths than 128-bit, though I don't know any specific on timelines.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks for the comments. Updated with the following:

  • Added context2.S changes
  • Removed store/restore of Z registers (as we only support 128bits for now, which fully overlap the V registers)
  • Added a XStateFeaturesMask to the Arm64 context so that we can tell whether to use SVE or not.

I'm currently unsure where else SVE state might need saving/restoring

@a74nh

Copy link
Copy Markdown
ContributorAuthor

Things I'm unsure about:

  • What the LPCONTEXT should look like
  • If there are extra areas in coreclr that need covering
    • I think AOT needs convering too. But SVE is no yet supported in AOT
    • Do the SVE registers need propagating anywhere else?
  • Is there a testsuite for this?

@a74nh
a74nh marked this pull request as ready for review June 21, 2024 13:22
@a74nh

Copy link
Copy Markdown
ContributorAuthor

Build failures on Windows, but I expected that as that all still needs doing. Marking as ready as I could do with comments, especially on the Windows side.

@dotnet/arm64-contrib @kunalspathak@tannergooding

@kunalspathakkunalspathak added the arm-sve Work related to arm64 SVE/SVE2 support label Jun 21, 2024
@kunalspathak

Copy link
Copy Markdown
Contributor

@JasonLinMS

Comment threadsrc/coreclr/debug/inc/dbgtargetcontext.h Outdated
Comment threadsrc/coreclr/pal/inc/pal.h Outdated
Comment threadsrc/coreclr/pal/src/arch/arm64/context2.S Outdated
}
}

if (sve)

@janvorlijanvorliJun 27, 2024

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.

Similar to x64, we should copy the state only if the contextFlags has the CONTEXT_XSTATE flag set. The passed in contextFlags list parts of the state that are valid that the caller is interested in.

It seems it would make sense to move this to the end of the function next to where we extract xstate for amd64 and put it under the same if ((contextFlags & CONTEXT_XSTATE) == CONTEXT_XSTATE).

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Similar to x64, we should copy the state only if the contextFlags has the CONTEXT_XSTATE flag set.

There is one remaining test failure I've just debugged to being due to this. Will fix it up.

sub x0, x0, CONTEXT_FLOAT_CONTROL_OFFSET + CONTEXT_NEON_OFFSET

LOCAL_LABEL(Done_CONTEXT_FLOATING_POINT):
ldr x1, [x0, CONTEXT_XSTATEFEATURESMASK_OFFSET]

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.

It should check the CONTEXT_XSTATE in CONTEXT_ContextFlags first and check the features mask only if the CONTEXT_XSTATE is set.

// since we potentially clobber x0 below, we'll bank it in x16
mov x16, x0

ldr w17, [x16, CONTEXT_XSTATEFEATURESMASK_OFFSET]

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.

It should check the CONTEXT_XSTATE in CONTEXT_ContextFlags first and check the features mask only if the CONTEXT_XSTATE is set.

#endif // XSTATE_SUPPORTED || (HOST_AMD64 && HAVE_MACH_EXCEPTIONS)

#if defined(HOST_64BIT) && defined(HOST_ARM64) && !defined(TARGET_FREEBSD) && !defined(TARGET_OSX)
#if !defined(SVE_MAGIC)

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.

Is this define not present when building in our CI?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Is this define not present when building in our CI?

Yes, they are missing in the CI. If I remove any of them the build falls over. I think this is when cross compiling. Eithe way, it must be an old Linux being used because these defines have been present in Linux since about 2017.

@janvorli

Copy link
Copy Markdown
Member

Besides the few comments, it looks good.

@a74nh

Copy link
Copy Markdown
ContributorAuthor

Fixed up so that XSTATE is set and checked as suggested.
Everything in run.sh passes and I can see state getting copied when debugging around signals.

This PR enables -DXSTATE_SUPPORTED on Arm64. Am I correct in thinking that on AMD64 Windows this flag is also used in certain scenarios to ensure the xstate data is block copied? If that is the case, then on Arm64 Windows this support still needs adding - probably by just enabling some AMD64 defines for ARM64. However, I've not go a windows setup and so don't want to blindly do anything here and recommend someone checks windows this after this PR is merged.

@a74nh

Copy link
Copy Markdown
ContributorAuthor

Running all priority 1 tests in checked on SVE Linux....

Time [secs] | Total | Passed | Failed | Skipped | Assembly Execution Summary
============================================================================
30.836 | 131 | 131 | 0 | 0 | JIT.Regression.Regression_4
13.873 | 345 | 342 | 0 | 3 | JIT.Regression.Regression_3
13.446 | 53 | 53 | 0 | 0 | CoreMangLib.CoreMangLib
11.249 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests900-999
13.538 | 76 | 76 | 0 | 0 | GC.API.XUnitWrapper.dll
1.225 | 3 | 3 | 0 | 0 | GC.Coverage.XUnitWrapper.dll
183.980 | 42 | 42 | 0 | 0 | GC.Features.XUnitWrapper.dll
3.100 | 6 | 6 | 0 | 0 | GC.LargeMemory.XUnitWrapper.dll
4.731 | 12 | 12 | 0 | 0 | GC.Regressions.XUnitWrapper.dll
22.314 | 481 | 481 | 0 | 0 | GC.Scenarios.XUnitWrapper.dll
0.039 | 1 | 1 | 0 | 0 | GC.Stress.XUnitWrapper.dll
0.534 | 1 | 1 | 0 | 0 | ilasm.PortablePdb.XUnitWrapper.dll
0.619 | 1 | 1 | 0 | 0 | ilasm.System.XUnitWrapper.dll
2.668 | 1 | 1 | 0 | 0 | ilverify.XUnitWrapper.dll
0.537 | 2 | 2 | 0 | 0 | profiler.assembly.XUnitWrapper.dll
1.236 | 2 | 2 | 0 | 0 | profiler.elt.XUnitWrapper.dll
0.793 | 3 | 3 | 0 | 0 | profiler.eventpipe.XUnitWrapper.dll
0.983 | 4 | 4 | 0 | 0 | profiler.gc.XUnitWrapper.dll
0.557 | 1 | 1 | 0 | 0 | profiler.handles.XUnitWrapper.dll
0.038 | 1 | 1 | 0 | 0 | profiler.multiple.XUnitWrapper.dll
0.037 | 1 | 1 | 0 | 0 | profiler.rejit.XUnitWrapper.dll
1.360 | 1 | 1 | 0 | 0 | profiler.transitions.XUnitWrapper.dll
4.133 | 5 | 5 | 0 | 0 | profiler.unittest.XUnitWrapper.dll
0.117 | 1 | 0 | 0 | 1 | JIT.jit64.jit64_2
5.451 | 116 | 116 | 0 | 0 | JIT.SIMD.JIT.SIMD
6.433 | 101 | 101 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests1400-1599
4.025 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests200-299
10.097 | 230 | 227 | 1 | 2 | JIT.Directed.Directed_3
19.526 | 214 | 214 | 0 | 0 | JIT.Directed.Directed_1
5.211 | 216 | 216 | 0 | 0 | JIT.Generics.JIT.Generics
8.080 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests1200-1299
12.593 | 16 | 16 | 0 | 0 | reflection.reflection
138.821 | 100 | 100 | 0 | 0 | JIT.Performance.JIT.performance
172.627 | 11 | 11 | 0 | 0 | JIT.JIT_others
2.365 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests0-99
1.128 | 2 | 1 | 0 | 1 | Exceptions.Exceptions
60.075 | 88 | 88 | 0 | 0 | baseservices.threading.threading_group2
2.885 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests500-599
158.641 | 322 | 321 | 0 | 1 | Loader.Loader
17.855 | 226 | 207 | 0 | 19 | Interop.Interop
5.244 | 437 | 433 | 0 | 4 | JIT.Regression.Regression_6
8.702 | 641 | 641 | 0 | 0 | JIT.CodeGenBringUpTests.JIT.CodeGenBringUpTests
6.596 | 16 | 16 | 0 | 0 | JIT.JIT_r
23.990 | 482 | 480 | 0 | 2 | JIT.Regression.Regression_1
8.302 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests700-799
0.522 | 3 | 3 | 0 | 0 | JIT.JIT_do
9.039 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests1100-1199
2.658 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests400-499
48.146 | 112 | 112 | 0 | 0 | JIT.jit64.jit64_1
84.672 | 1 | 1 | 0 | 0 | readytorun.coreroot_determinism.readytorun_coreroot_determinism
13.396 | 215 | 215 | 0 | 0 | Loader.classloader.generics.LoaderClassloaderGenerics
2.474 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests100-199
43.988 | 2551 | 2551 | 0 | 0 | JIT.HardwareIntrinsics.HardwareIntrinsics_General_ro
9.626 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests1300-1399
76.360 | 75 | 75 | 0 | 0 | Regressions.Regressions
5.244 | 211 | 210 | 0 | 1 | JIT.Methodical.Methodical_r2
5.458 | 85 | 85 | 0 | 0 | JIT.Methodical.Methodical_ro
9.593 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests800-899
75.522 | 20 | 18 | 0 | 2 | readytorun.readytorun
12.881 | 279 | 279 | 0 | 0 | JIT.Methodical.Methodical_r1
3.120 | 343 | 343 | 0 | 0 | JIT.jit64.jit64_4
1.532 | 47 | 47 | 0 | 0 | JIT.Regression.Regression_5
41.352 | 144 | 142 | 0 | 2 | baseservices.exceptions.baseservices-exceptions
9.289 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests1000-1099
18.946 | 67 | 67 | 0 | 0 | Loader.classloader.regressions.LoaderClassloaderRegressions
83.636 | 355 | 353 | 0 | 2 | JIT.opt.JIT.opt
5.979 | 85 | 85 | 0 | 0 | JIT.Methodical.Methodical_do
4.367 | 35 | 33 | 0 | 2 | tracing.tracing
37.561 | 485 | 484 | 0 | 1 | JIT.Regression.Regression_2
13.844 | 276 | 276 | 0 | 0 | JIT.Methodical.Methodical_d1
0.467 | 2 | 2 | 0 | 0 | JIT.JIT_d
92.261 | 143 | 139 | 0 | 4 | JIT.jit64.jit64_3
6.514 | 16 | 16 | 0 | 0 | JIT.JIT_ro
50.519 | 39 | 35 | 0 | 4 | baseservices.baseservices
7.336 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests600-699
5.981 | 208 | 207 | 0 | 1 | JIT.Methodical.Methodical_d2
35.809 | 231 | 226 | 0 | 5 | JIT.jit64.jit64_5
49.200 | 2584 | 2584 | 0 | 0 | JIT.HardwareIntrinsics.HardwareIntrinsics_General_r
1.555 | 55 | 54 | 0 | 1 | JIT.Methodical.Methodical_others
3.838 | 100 | 100 | 0 | 0 | Loader.classloader.TypeGeneratorTests.TypeGeneratorTests300-399
0.088 | 0 | 0 | 0 | 0 | managed.Managed
54.354 | 203 | 199 | 0 | 4 | JIT.Directed.Directed_2
2.741 | 405 | 405 | 0 | 0 | JIT.IL_Conformance.IL_Conformance
77.532 | 82 | 81 | 0 | 1 | baseservices.threading.threading_group1
----------------------------------------------------------------------------
1997.991 | 15149 | 15085 | 1 | 63 | (total)

That single failure I get on latest head, so I'm not worried about it.

Comment threadsrc/coreclr/pal/src/arch/arm64/context2.S
@jkotas

Copy link
Copy Markdown
Member

I see a lot of TODOs about SVE size being hardcoded to 128 bit.

What is going to be the experience when somebody runs .NET 9 binary on a machine with 256 bit SVE? It is important that it just works, without crashing, buffer overruns, etc.

@a74nh

Copy link
Copy Markdown
ContributorAuthor

I see a lot of TODOs about SVE size being hardcoded to 128 bit.

What is going to be the experience when somebody runs .NET 9 binary on a machine with 256 bit SVE? It is important that it just works, without crashing, buffer overruns, etc.

Running the entire testsuite on 256bit, all the tests pass with and without my latest fix. That's because there is no SVE state in the kernel, so that structure that comes back from the OS has no SVE state (sve.size is 16, it's just the header with no data).

Comment threadsrc/coreclr/pal/src/arch/arm64/asmconstants.h

@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.

Thanks @a74nh for your contribution. LGTM.

@kunalspathak

Copy link
Copy Markdown
Contributor

/ba-g failure is #103550

@kunalspathak
kunalspathak merged commit 9528c15 into dotnet:mainJun 29, 2024
akoeplinger added a commit to akoeplinger/runtime that referenced this pull request Jul 8, 2024
It got broken by dotnet#103801 due to a host vs. target arch typo.
This showed up in the VMR since we use arm64 macOS build agents there.
akoeplinger added a commit to akoeplinger/runtime that referenced this pull request Jul 8, 2024
It got uncovered by dotnet#103801.
This showed up in the VMR since we use arm64 macOS build agents there.
akoeplinger added a commit that referenced this pull request Jul 8, 2024
It got uncovered by #103801.
This showed up in the VMR since we use arm64 macOS build agents there.
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jul 29, 2024
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-PAL-coreclronly for closed issuesarm-sveWork related to arm64 SVE/SVE2 supportcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@a74nh@kunalspathak@janvorli@jkotas@JasonLinMS