From 76f7393e3638d672353092b02c53e5e261472854 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 10 Mar 2026 20:18:43 +0000 Subject: [PATCH 1/7] Initial plan From ac80f9ee6d08064b911dbc89f226a2ac194d04b5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 10 Mar 2026 20:50:54 +0000 Subject: [PATCH 2/7] Enable runtime-async for netcoreapp source projects excluding OOB, pre-net11, browser/wasm, and mobile Co-authored-by: agocke <515774+agocke@users.noreply.github.com> --- src/libraries/Directory.Build.targets | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/libraries/Directory.Build.targets b/src/libraries/Directory.Build.targets index 947dbfc3e71a66..674ffe7dd24617 100644 --- a/src/libraries/Directory.Build.targets +++ b/src/libraries/Directory.Build.targets @@ -127,8 +127,15 @@ '$(IsGeneratorProject)' != 'true'">true - - + + true $(Features);runtime-async=on From 6ffe3ab43621d9681adc6f0fe81f8805ab925ef5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Mar 2026 11:24:15 +0000 Subject: [PATCH 3/7] Factor RuntimeAsyncSupported, remove TestReadyToRun gate, delete UNSUPPORTED_RuntimeAsync config and DOTNET_RuntimeAsync env var Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- eng/testing/tests.targets | 16 ++++++++++------ src/coreclr/inc/clrconfigvalues.h | 3 --- src/coreclr/vm/eeconfig.cpp | 4 +--- src/libraries/Directory.Build.targets | 15 ++++++++++----- .../Interop/COM/RuntimeAsync/RuntimeAsync.csproj | 5 ----- 5 files changed, 21 insertions(+), 22 deletions(-) diff --git a/eng/testing/tests.targets b/eng/testing/tests.targets index 1dd5cdd9dfbdaa..b14cabb2b8d1c2 100644 --- a/eng/testing/tests.targets +++ b/eng/testing/tests.targets @@ -1,14 +1,18 @@ + + + true + + true $(Features);runtime-async=on diff --git a/src/coreclr/inc/clrconfigvalues.h b/src/coreclr/inc/clrconfigvalues.h index fd64be3df1b59f..78d11c697a1e88 100644 --- a/src/coreclr/inc/clrconfigvalues.h +++ b/src/coreclr/inc/clrconfigvalues.h @@ -715,9 +715,6 @@ RETAIL_CONFIG_DWORD_INFO(EXTERNAL_EnableRiscV64Zbb, W("EnableRiscV64 RETAIL_CONFIG_DWORD_INFO(EXTERNAL_EnableRiscV64Zbs, W("EnableRiscV64Zbs"), 1, "Allows RiscV64 Zbs hardware intrinsics to be disabled") #endif -// Runtime-async -RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_RuntimeAsync, W("RuntimeAsync"), 1, "Enables runtime async method support") - /// /// Uncategorized /// diff --git a/src/coreclr/vm/eeconfig.cpp b/src/coreclr/vm/eeconfig.cpp index 776febb4045381..7a1846f29aef73 100644 --- a/src/coreclr/vm/eeconfig.cpp +++ b/src/coreclr/vm/eeconfig.cpp @@ -233,7 +233,7 @@ HRESULT EEConfig::Init() fGDBJitEmitDebugFrame = false; #endif - runtimeAsync = false; + runtimeAsync = true; return S_OK; } @@ -848,8 +848,6 @@ HRESULT EEConfig::sync() fUseCachedInterfaceDispatch = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_UseCachedInterfaceDispatch) != 0; #endif // defined(FEATURE_CACHED_INTERFACE_DISPATCH) && defined(FEATURE_VIRTUAL_STUB_DISPATCH) - runtimeAsync = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_RuntimeAsync) != 0; - return hr; } diff --git a/src/libraries/Directory.Build.targets b/src/libraries/Directory.Build.targets index 674ffe7dd24617..32287b87d19ac7 100644 --- a/src/libraries/Directory.Build.targets +++ b/src/libraries/Directory.Build.targets @@ -127,15 +127,20 @@ '$(IsGeneratorProject)' != 'true'">true + + + true + + + and '$(RuntimeAsyncSupported)' == 'true'"> true $(Features);runtime-async=on diff --git a/src/tests/Interop/COM/RuntimeAsync/RuntimeAsync.csproj b/src/tests/Interop/COM/RuntimeAsync/RuntimeAsync.csproj index 4a015bc375e61e..c3dcb6a823d350 100644 --- a/src/tests/Interop/COM/RuntimeAsync/RuntimeAsync.csproj +++ b/src/tests/Interop/COM/RuntimeAsync/RuntimeAsync.csproj @@ -1,7 +1,5 @@ - - true $(Features);runtime-async=on @@ -13,7 +11,4 @@ - - - From c10423f0026ec0fc925c5cc660a7dc573ed88ab5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Mar 2026 11:25:28 +0000 Subject: [PATCH 4/7] Add comment explaining runtimeAsync is always enabled Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- src/coreclr/vm/eeconfig.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/coreclr/vm/eeconfig.cpp b/src/coreclr/vm/eeconfig.cpp index 7a1846f29aef73..0650cd0748955f 100644 --- a/src/coreclr/vm/eeconfig.cpp +++ b/src/coreclr/vm/eeconfig.cpp @@ -233,6 +233,7 @@ HRESULT EEConfig::Init() fGDBJitEmitDebugFrame = false; #endif + // Runtime async is always enabled; the UNSUPPORTED_RuntimeAsync config knob has been removed. runtimeAsync = true; return S_OK; From cffb194dca55895a81f4ce6b1e117f3b9e8eb256 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Mar 2026 14:40:31 +0000 Subject: [PATCH 5/7] Remove runtimeAsync field, RuntimeAsync() method, and its caller guard Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- src/coreclr/vm/eeconfig.cpp | 3 --- src/coreclr/vm/eeconfig.h | 4 ---- src/coreclr/vm/method.cpp | 7 ------- 3 files changed, 14 deletions(-) diff --git a/src/coreclr/vm/eeconfig.cpp b/src/coreclr/vm/eeconfig.cpp index 0650cd0748955f..97cc3a04c58df2 100644 --- a/src/coreclr/vm/eeconfig.cpp +++ b/src/coreclr/vm/eeconfig.cpp @@ -233,9 +233,6 @@ HRESULT EEConfig::Init() fGDBJitEmitDebugFrame = false; #endif - // Runtime async is always enabled; the UNSUPPORTED_RuntimeAsync config knob has been removed. - runtimeAsync = true; - return S_OK; } diff --git a/src/coreclr/vm/eeconfig.h b/src/coreclr/vm/eeconfig.h index fecb76eb69fb41..d57ea26c4bc1d5 100644 --- a/src/coreclr/vm/eeconfig.h +++ b/src/coreclr/vm/eeconfig.h @@ -449,8 +449,6 @@ class EEConfig #endif - bool RuntimeAsync() const { LIMITED_METHOD_CONTRACT; return runtimeAsync; } - #ifdef FEATURE_INTERPRETER bool EnableInterpreter() const { LIMITED_METHOD_CONTRACT; return enableInterpreter; } #endif @@ -654,8 +652,6 @@ class EEConfig bool fUseCachedInterfaceDispatch; #endif // defined(FEATURE_CACHED_INTERFACE_DISPATCH) && defined(FEATURE_VIRTUAL_STUB_DISPATCH) - bool runtimeAsync; // True if the runtime supports async methods - public: enum BitForMask { diff --git a/src/coreclr/vm/method.cpp b/src/coreclr/vm/method.cpp index 32d9a717280647..b11a65865c1bda 100644 --- a/src/coreclr/vm/method.cpp +++ b/src/coreclr/vm/method.cpp @@ -2392,13 +2392,6 @@ bool IsTypeDefOrRefImplementedInSystemModule(Module* pModule, mdToken tk) MethodReturnKind ClassifyMethodReturnKind(SigPointer sig, Module* pModule, ULONG* offsetOfAsyncDetails, bool *isValueTask) { - // Without runtime async, every declared method is classified as a NormalMethod. - // Thus code that handles runtime async scenarios becomes unreachable. - if (!g_pConfig->RuntimeAsync()) - { - return MethodReturnKind::NormalMethod; - } - PCCOR_SIGNATURE initialSig = sig.GetPtr(); uint32_t data; IfFailThrow(sig.GetCallingConvInfo(&data)); From 55a587604283f4df2a9674fcb77cad0c232250fb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Mar 2026 18:33:15 +0000 Subject: [PATCH 6/7] Exclude OOB assemblies (IsPackable=true) from runtime-async enablement Co-authored-by: agocke <515774+agocke@users.noreply.github.com> --- src/libraries/Directory.Build.targets | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libraries/Directory.Build.targets b/src/libraries/Directory.Build.targets index 32287b87d19ac7..87342ee832c6f6 100644 --- a/src/libraries/Directory.Build.targets +++ b/src/libraries/Directory.Build.targets @@ -136,8 +136,9 @@ and '$(RuntimeFlavor)' != 'Mono'">true - + From cd8b1e4194ef67d023367f58ab38cfcfd4af7f44 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Mar 2026 22:56:28 +0000 Subject: [PATCH 7/7] Merge main and resolve conflict in eng/testing/tests.targets Co-authored-by: agocke <515774+agocke@users.noreply.github.com> --- .config/dotnet-tools.json | 2 +- .github/copilot-instructions.md | 11 +- THIRD-PARTY-NOTICES.TXT | 33 + docs/design/coreclr/botr/clr-abi.md | 1 + docs/design/datacontracts/BuiltInCOM.md | 56 +- docs/design/datacontracts/Loader.md | 8 +- eng/Version.Details.props | 6 +- eng/Version.Details.xml | 12 +- .../runtime-extra-platforms-ioslike.yml | 2 +- ...ntime-extra-platforms-ioslikesimulator.yml | 2 +- .../runtime-extra-platforms-maccatalyst.yml | 4 +- eng/testing/BrowserVersions.props | 2 +- src/coreclr/interpreter/compiler.cpp | 2 - src/coreclr/jit/codegen.h | 7 +- src/coreclr/jit/codegenlinear.cpp | 10 + src/coreclr/jit/codegenloongarch64.cpp | 96 +-- src/coreclr/jit/codegenwasm.cpp | 25 +- src/coreclr/jit/compiler.h | 13 + src/coreclr/jit/compiler.hpp | 61 +- src/coreclr/jit/emit.cpp | 5 +- src/coreclr/jit/emitloongarch64.cpp | 31 +- src/coreclr/jit/gentree.cpp | 38 +- src/coreclr/jit/hwintrinsic.cpp | 16 +- src/coreclr/jit/hwintrinsiccodegenarm64.cpp | 73 ++ src/coreclr/jit/hwintrinsiclistarm64sve.h | 20 +- src/coreclr/jit/ifconversion.cpp | 100 +-- src/coreclr/jit/importer.cpp | 5 +- src/coreclr/jit/lclmorph.cpp | 46 +- src/coreclr/jit/lclvars.cpp | 8 +- src/coreclr/jit/lower.cpp | 4 +- src/coreclr/jit/lsraarm64.cpp | 5 + src/coreclr/jit/morph.cpp | 70 +- src/coreclr/jit/utils.h | 3 +- .../nativeaot/Runtime/loongarch64/GcProbe.S | 37 +- .../Runtime/unix/unixasmmacrosloongarch64.inc | 1 + src/coreclr/scripts/superpmi.py | 3 +- .../DependencyAnalysis/AssemblyStubNode.cs | 3 + .../INodeWithTypeSignature.cs | 18 + .../Compiler/DependencyAnalysis/ObjectNode.cs | 8 + .../Compiler/DependencyAnalysis/Relocation.cs | 6 +- .../Target_Wasm/WasmTypes.cs | 1 + .../{Target_Wasm => }/WasmTypeNode.cs | 5 +- .../Compiler/ObjectWriter/ObjectWriter.cs | 31 +- .../Compiler/ObjectWriter/PEObjectWriter.cs | 7 +- .../Compiler/ObjectWriter/WasmNative.cs | 1 + .../Compiler/ObjectWriter/WasmObjectWriter.cs | 13 +- .../tools/Common/JitInterface/WasmLowering.cs | 2 + .../DependencyAnalysis/NodeFactory.cs | 17 + .../ILCompiler.Compiler.csproj | 3 +- .../ReadyToRun/DelayLoadHelperMethodImport.cs | 2 +- .../ReadyToRun/DelayLoadMethodImport.cs | 2 +- .../ReadyToRun/MethodWithGCInfo.cs | 2 +- .../ReadyToRun/Target_Wasm/ImportThunk.cs | 1 + .../ReadyToRunCodegenNodeFactory.cs | 8 + .../ILCompiler.ReadyToRun.csproj | 3 +- .../JitInterface/CorInfoImpl.ReadyToRun.cs | 1 + .../DependencyAnalysis/MethodCodeNode.cs | 2 +- src/coreclr/utilcode/util.cpp | 4 + src/coreclr/vm/appdomain.cpp | 6 +- src/coreclr/vm/comcache.h | 9 + .../vm/datadescriptor/datadescriptor.inc | 8 + src/coreclr/vm/loongarch64/asmhelpers.S | 12 +- src/coreclr/vm/loongarch64/cgencpu.h | 5 + src/coreclr/vm/loongarch64/stubs.cpp | 2 + src/coreclr/vm/prestub.cpp | 5 + src/coreclr/vm/runtimecallablewrapper.h | 2 +- .../src/SourceGenerators/DiagnosticInfo.cs | 60 -- .../Cryptography/Asn1Reader/AsnValueReader.cs | 258 ------- .../AsnWriter/AsnWriterExtensions.cs | 38 + ...y.Cryptography.AsnWriter.Shared.projitems} | 4 +- .../Security/Cryptography/RSAOpenSsl.cs | 47 +- .../CompositeMLDsaTestHelpers.cs | 4 +- .../src/Microsoft.Bcl.Cryptography.csproj | 2 +- .../Microsoft.Bcl.Cryptography.Tests.csproj | 2 +- .../ConfigurationBindingGenerator.Parser.cs | 10 +- .../gen/ConfigurationBindingGenerator.cs | 45 +- ...nfiguration.Binder.SourceGeneration.csproj | 1 - .../SourceGenerationTests/GeneratorTests.cs | 125 ++++ .../gen/LoggerMessageGenerator.Parser.cs | 10 +- .../gen/LoggerMessageGenerator.Roslyn4.0.cs | 127 ++-- ...soft.Extensions.Logging.Generators.targets | 1 - .../LoggerMessageGeneratorParserTests.cs | 31 + .../Net/NetworkInformation/Ping.Windows.cs | 12 +- .../tests/FunctionalTests/PingTest.cs | 56 ++ .../src/System.Net.Security.csproj | 2 - ...egotiateAuthenticationPal.ManagedSpnego.cs | 12 +- .../Arm/Sve.PlatformNotSupported.cs | 124 ---- .../src/System/Runtime/Intrinsics/Arm/Sve.cs | 124 ---- .../Arm/Sve2.PlatformNotSupported.cs | 578 +++++++++++++++ .../src/System/Runtime/Intrinsics/Arm/Sve2.cs | 578 +++++++++++++++ .../ComClassGeneratorDiagnosticsAnalyzer.cs | 106 +++ .../ComClassGenerator.cs | 26 +- .../gen/ComInterfaceGenerator/ComClassInfo.cs | 36 +- .../DiagnosticOr.cs | 26 - ...eneratorInitializationContextExtensions.cs | 20 - .../ComClassGeneratorDiagnostics.cs | 110 ++- .../ComClassGeneratorOutputShape.cs | 10 +- .../ref/System.Runtime.Intrinsics.cs | 109 ++- .../Directory/Delete_MountVolume.cs | 28 +- .../System.Security.Cryptography.Pkcs.csproj | 2 +- .../src/System.Security.Cryptography.csproj | 2 +- .../System.Security.Cryptography.Tests.csproj | 2 +- .../gen/JsonSourceGenerator.Parser.cs | 4 +- .../gen/JsonSourceGenerator.Roslyn3.11.cs | 4 +- .../gen/JsonSourceGenerator.Roslyn4.0.cs | 48 +- .../System.Text.Json.SourceGeneration.targets | 1 - .../JsonSourceGeneratorDiagnosticsTests.cs | 29 + .../JsonSourceGeneratorIncrementalTests.cs | 1 - .../gen/RegexGenerator.Parser.cs | 40 +- .../gen/RegexGenerator.cs | 132 ++-- .../RegexGeneratorHelper.netcoreapp.cs | 2 +- .../RegexGeneratorParserTests.cs | 22 + ...iCompatBaseline.NetCoreAppLatestStable.xml | 96 +++ .../App/Layout/NavMenu.razor | 2 +- .../Contracts/IBuiltInCOM.cs | 2 + .../DataType.cs | 1 + .../Constants.cs | 1 + .../Contracts/BuiltInCOM_1.cs | 19 + .../Contracts/Loader_1.cs | 3 +- .../Data/InterfaceEntry.cs | 19 + .../Data/RCW.cs | 14 + .../ClrDataAppDomain.cs | 130 +++- .../ClrDataFrame.cs | 92 ++- .../ClrDataTask.cs | 2 +- .../ISOSDacInterface.cs | 16 +- .../IXCLRData.cs | 4 +- .../SOSDacImpl.cs | 91 ++- .../managed/cdac/tests/BuiltInCOMTests.cs | 211 ++++++ .../Debuggees/RCWInterfaces/Program.cs | 119 +++ .../RCWInterfaces/RCWInterfaces.csproj | 7 + .../DumpTests/Debuggees/StackWalk/Program.cs | 18 +- .../cdac/tests/DumpTests/DumpTestBase.cs | 16 +- .../DumpTests/IXCLRDataAppDomainDumpTests.cs | 218 ++++++ .../DumpTests/IXCLRDataFrameDumpTests.cs | 308 ++++++++ .../tests/DumpTests/RCWInterfacesDumpTests.cs | 75 ++ .../GenerateHWIntrinsicTests/Arm/Sve2Tests.cs | 101 +++ .../GenerateHWIntrinsicTests/Arm/SveTests.cs | 18 - .../Github/Runtime_76219/Runtime_76219.csproj | 3 + .../JIT/Methodical/Boxing/morph/sin3double.il | 6 - .../flowgraph/bug619534/moduleHandleCache.cs | 2 - src/tests/JIT/Methodical/switch/switch6.il | 7 - .../JIT/opt/InstructionCombining/Casts.cs | 694 ++++++++++++++++++ .../JIT/opt/InstructionCombining/Casts.csproj | 17 + src/tests/nativeaot/Directory.Build.props | 6 - src/tests/nativeaot/Directory.Build.targets | 13 - .../MobileSmokeTest/MobileSmokeTest.cs | 28 + .../MobileSmokeTest/MobileSmokeTest.csproj | 14 + .../nativeaot/StartupHook/StartupHook.csproj | 2 +- src/tests/nativeaot/nativeaot.csproj | 7 + .../TestFrameworkTests.g.cs | 12 + .../Assertions/KeptAttributeAttribute.cs | 13 + .../Reflection/TypeMap.cs | 25 +- .../VerifyKeptAttributeAttributeWorks.cs | 310 ++++++++ .../TestFramework/VerifyLocalsAreChanged.cs | 44 ++ .../TestFramework/VerifyLocalsAreChanged.xml | 11 + .../TestCasesRunner/AssemblyChecker.cs | 170 ++++- 156 files changed, 5630 insertions(+), 1355 deletions(-) create mode 100644 src/coreclr/tools/Common/Compiler/DependencyAnalysis/INodeWithTypeSignature.cs rename src/coreclr/tools/Common/Compiler/DependencyAnalysis/{Target_Wasm => }/WasmTypeNode.cs (96%) delete mode 100644 src/libraries/Common/src/SourceGenerators/DiagnosticInfo.cs delete mode 100644 src/libraries/Common/src/System/Security/Cryptography/Asn1Reader/AsnValueReader.cs create mode 100644 src/libraries/Common/src/System/Security/Cryptography/AsnWriter/AsnWriterExtensions.cs rename src/libraries/Common/src/System/Security/Cryptography/{Asn1Reader/System.Security.Cryptography.Asn1Reader.Shared.projitems => AsnWriter/System.Security.Cryptography.AsnWriter.Shared.projitems} (66%) create mode 100644 src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Analyzers/ComClassGeneratorDiagnosticsAnalyzer.cs create mode 100644 src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/InterfaceEntry.cs create mode 100644 src/native/managed/cdac/tests/DumpTests/Debuggees/RCWInterfaces/Program.cs create mode 100644 src/native/managed/cdac/tests/DumpTests/Debuggees/RCWInterfaces/RCWInterfaces.csproj create mode 100644 src/native/managed/cdac/tests/DumpTests/IXCLRDataAppDomainDumpTests.cs create mode 100644 src/native/managed/cdac/tests/DumpTests/IXCLRDataFrameDumpTests.cs create mode 100644 src/native/managed/cdac/tests/DumpTests/RCWInterfacesDumpTests.cs create mode 100644 src/tests/JIT/opt/InstructionCombining/Casts.cs create mode 100644 src/tests/JIT/opt/InstructionCombining/Casts.csproj delete mode 100644 src/tests/nativeaot/Directory.Build.targets create mode 100644 src/tests/nativeaot/MobileSmokeTest/MobileSmokeTest.cs create mode 100644 src/tests/nativeaot/MobileSmokeTest/MobileSmokeTest.csproj create mode 100644 src/tests/nativeaot/nativeaot.csproj create mode 100644 src/tools/illink/test/Mono.Linker.Tests.Cases/TestFramework/VerifyKeptAttributeAttributeWorks.cs create mode 100644 src/tools/illink/test/Mono.Linker.Tests.Cases/TestFramework/VerifyLocalsAreChanged.cs create mode 100644 src/tools/illink/test/Mono.Linker.Tests.Cases/TestFramework/VerifyLocalsAreChanged.xml diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 380e3141ecebc9..6b46169cb36d04 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -15,7 +15,7 @@ ] }, "microsoft.dotnet.xharness.cli": { - "version": "11.0.0-prerelease.26064.3", + "version": "11.0.0-prerelease.26160.2", "commands": [ "xharness" ] diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index f405371e14de23..d3c1221e713383 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -8,7 +8,9 @@ You MUST make your best effort to ensure any code changes satisfy those criteria If you make code changes, do not complete without checking the relevant code builds and relevant tests still pass after the last edits you make. Do not simply assume that your changes fix test failures you see, actually build and run those tests again to confirm. -Before completing, use the `code-review` skill to review your code changes. Any issues flagged as errors or warnings should be addressed before completing. +When running under CCA and before completing, use the `code-review` skill to review your code changes. Any issues flagged as errors or warnings should be addressed before the task is considered complete. + +When NOT running under CCA, skip the `code-review` skill if the user has stated they will review the changes themselves. Before making changes to a directory, search for `README.md` files in that directory and its parent directories up to the repository root. Read any you find — they contain conventions, patterns, and architectural context relevant to your work. @@ -38,6 +40,13 @@ In addition to the rules enforced by `.editorconfig`, you SHOULD: - For markdown (`.md`) files, ensure there is no trailing whitespace at the end of any line. - When adding XML documentation to APIs, follow the guidelines at [`docs.prompt.md`](/.github/prompts/docs.prompt.md). +When NOT running under CCA, guidance for creating commits and pushing changes: + +- Never squash and force push unless explicitly instructed. Always push incremental commits on top of previous PR changes. +- Never push to an active PR without being explicitly asked, even in autopilot/yolo mode. Always wait for explicit instruction to push. +- Never chain commit and push in the same command. Always commit first, report what was committed, then wait for an explicit push instruction. This creates a mandatory decision point. +- Prefer creating a new commit rather than amending an existing one. Exceptions: (1) explicitly asked to amend, or (2) the existing commit is obviously broken with something minor (e.g., typo or comment fix) and hasn't been pushed yet. + --- # Building & Testing in dotnet/runtime diff --git a/THIRD-PARTY-NOTICES.TXT b/THIRD-PARTY-NOTICES.TXT index 033db7e5e46e5d..7f020cf8e67da5 100644 --- a/THIRD-PARTY-NOTICES.TXT +++ b/THIRD-PARTY-NOTICES.TXT @@ -1424,3 +1424,36 @@ NIST-developed software is expressly provided "AS IS." NIST MAKES NO WARRANTY OF You are solely responsible for determining the appropriateness of using and distributing the software and you assume all risks associated with its use, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and the unavailability or interruption of operation. This software is not intended to be used in any situation where a failure could cause risk of injury or damage to property. The software developed by NIST employees is not subject to copyright protection within the United States. +License notice for ANTLR 4 +------------------------------- + +https://github.com/antlr/antlr4 + +Copyright (c) 2012-2022 The ANTLR Project. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither name of copyright holders nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/docs/design/coreclr/botr/clr-abi.md b/docs/design/coreclr/botr/clr-abi.md index 889a4c9cde656b..3f1cf8dd3fa090 100644 --- a/docs/design/coreclr/botr/clr-abi.md +++ b/docs/design/coreclr/botr/clr-abi.md @@ -116,6 +116,7 @@ To return `Continuation` we use a volatile/calee-trash register that cannot be u | arm | r2 | | arm64 | x2 | | risc-v | a2 | +| loongarch64 | a2 | ### Passing `Continuation` argument The `Continuation` parameter is passed at the same position as generic instantiation parameter or immediately after, if both present. For x86 the argument order is reversed. diff --git a/docs/design/datacontracts/BuiltInCOM.md b/docs/design/datacontracts/BuiltInCOM.md index 4e7cae7200443b..c9e28915501d52 100644 --- a/docs/design/datacontracts/BuiltInCOM.md +++ b/docs/design/datacontracts/BuiltInCOM.md @@ -5,6 +5,20 @@ This contract is for getting information related to built-in COM. ## APIs of contract ``` csharp +public struct COMInterfacePointerData +{ + // Address of the slot in ComCallWrapper that holds the COM interface pointer. + public TargetPointer InterfacePointerAddress; + // MethodTable for this interface, or TargetPointer.Null for slot 0 (IUnknown/IDispatch). + public TargetPointer MethodTable; +} + +public record struct RCWCleanupInfo( + TargetPointer RCW, + TargetPointer Context, + TargetPointer STAThread, + bool IsFreeThreaded); + public ulong GetRefCount(TargetPointer ccw); // Check whether the COM wrappers handle is weak. public bool IsHandleWeak(TargetPointer ccw); @@ -14,20 +28,13 @@ public TargetPointer GetCCWFromInterfacePointer(TargetPointer interfacePointer); // Enumerate the COM interfaces exposed by the ComCallWrapper chain. // ccw may be any ComCallWrapper in the chain; the implementation navigates to the start. public IEnumerable GetCCWInterfaces(TargetPointer ccw); -``` - -where `COMInterfacePointerData` is: -``` csharp -public struct COMInterfacePointerData -{ - // Address of the slot in ComCallWrapper that holds the COM interface pointer. - public TargetPointer InterfacePointerAddress; - // MethodTable for this interface, or TargetPointer.Null for slot 0 (IUnknown/IDispatch). - public TargetPointer MethodTable; -} // Enumerate entries in the RCW cleanup list. // If cleanupListPtr is Null, the global g_pRCWCleanupList is used. public IEnumerable GetRCWCleanupList(TargetPointer cleanupListPtr); +// Enumerate the interface entries cached in an RCW. +public IEnumerable<(TargetPointer MethodTable, TargetPointer Unknown)> GetRCWInterfaces(TargetPointer rcw); +// Get the COM context cookie for an RCW. +public TargetPointer GetRCWContext(TargetPointer rcw); ``` ## Version 1 @@ -51,6 +58,9 @@ Data descriptors used: | `RCW` | `CtxCookie` | COM context cookie for the RCW | | `RCW` | `CtxEntry` | Pointer to `CtxEntry` (bit 0 is a synchronization flag; must be masked off before use) | | `CtxEntry` | `STAThread` | STA thread pointer for the context entry | +| `RCW` | `InterfaceEntries` | Offset of the inline interface entry cache array within the RCW struct | +| `InterfaceEntry` | `MethodTable` | MethodTable pointer for the cached COM interface | +| `InterfaceEntry` | `Unknown` | `IUnknown*` pointer for the cached COM interface | Global variables used: | Global Name | Type | Purpose | @@ -62,6 +72,7 @@ Global variables used: | `TearOffAddRefSimple` | pointer | Address of `Unknown_AddRefSpecial`; identifies `SimpleComCallWrapper` interface pointers | | `TearOffAddRefSimpleInner` | pointer | Address of `Unknown_AddRefInner`; identifies inner `SimpleComCallWrapper` interface pointers | | `RCWCleanupList` | `pointer` | Pointer to the global `g_pRCWCleanupList` instance | +| `RCWInterfaceCacheSize` | `uint32` | Number of entries in the inline interface entry cache (`INTERFACE_ENTRY_CACHE_SIZE`) | ### Contract Constants: | Name | Type | Purpose | Value | @@ -156,5 +167,28 @@ public IEnumerable GetRCWCleanupList(TargetPointer cleanupListPt bucketPtr = _target.ReadPointer(bucketPtr + /* RCW::NextCleanupBucket offset */); } } + +public IEnumerable<(TargetPointer MethodTable, TargetPointer Unknown)> GetRCWInterfaces(TargetPointer rcw) +{ + // InterfaceEntries is an inline array — the offset gives the address of the first element. + TargetPointer interfaceEntriesAddr = rcw + /* RCW::InterfaceEntries offset */; + uint cacheSize = _target.ReadGlobal("RCWInterfaceCacheSize"); + uint entrySize = /* size of InterfaceEntry */; + + for (uint i = 0; i < cacheSize; i++) + { + TargetPointer entryAddress = interfaceEntriesAddr + i * entrySize; + TargetPointer methodTable = _target.ReadPointer(entryAddress + /* InterfaceEntry::MethodTable offset */); + TargetPointer unknown = _target.ReadPointer(entryAddress + /* InterfaceEntry::Unknown offset */); + // An entry is free if Unknown == null (matches InterfaceEntry::IsFree()) + if (unknown != TargetPointer.Null) + yield return (methodTable, unknown); + } +} + +public TargetPointer GetRCWContext(TargetPointer rcw) +{ + return _target.ReadPointer(rcw + /* RCW::CtxCookie offset */); +} ``` diff --git a/docs/design/datacontracts/Loader.md b/docs/design/datacontracts/Loader.md index 0be000bb750063..95f1652cf1b805 100644 --- a/docs/design/datacontracts/Loader.md +++ b/docs/design/datacontracts/Loader.md @@ -182,6 +182,7 @@ IReadOnlyDictionary GetLoaderAllocatorHeaps(TargetPointer | Name | Type | Purpose | Value | | --- | --- | --- | --- | | `ASSEMBLY_NOTIFYFLAGS_PROFILER_NOTIFIED` | uint | Flag in Assembly NotifyFlags indicating the Assembly will notify profilers. | `0x1` | +| `DefaultDomainFriendlyName` | string | Friendly name returned when `AppDomain.FriendlyName` is null (matches native `DEFAULT_DOMAIN_FRIENDLY_NAME`) | `"DefaultDomain"` | Contracts used: | Contract Name | @@ -327,8 +328,11 @@ string ILoader.GetAppDomainFriendlyName() { TargetPointer appDomainPointer = target.ReadGlobalPointer("AppDomain"); TargetPointer appDomain = target.ReadPointer(appDomainPointer) - TargetPointer pathStart = appDomain + /* AppDomain::FriendlyName offset */; - char[] name = // Read from target starting at pathStart until null terminator + TargetPointer namePtr = appDomain + /* AppDomain::FriendlyName offset */; + // Match native AppDomain::GetFriendlyName(): return "DefaultDomain" when pointer is null. + if (namePtr == TargetPointer.Null) + return "DefaultDomain"; + char[] name = // Read from target starting at namePtr until null terminator return new string(name); } diff --git a/eng/Version.Details.props b/eng/Version.Details.props index b4f5bc132e70e3..a2269cd6d6c096 100644 --- a/eng/Version.Details.props +++ b/eng/Version.Details.props @@ -113,9 +113,9 @@ This file should be imported by eng/Versions.props 11.0.0-beta.26159.1 11.0.0-beta.26159.1 - 11.0.0-prerelease.26064.3 - 11.0.0-prerelease.26064.3 - 11.0.0-prerelease.26064.3 + 11.0.0-prerelease.26160.2 + 11.0.0-prerelease.26160.2 + 11.0.0-prerelease.26160.2 diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index d87a8ed73c30a3..e8afb73f0d2a56 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -287,17 +287,17 @@ https://github.com/dotnet/dotnet 5507d7a2f05bb6c073a055ead6ce1c4bbe396cda - + https://github.com/dotnet/xharness - 31e0b8e08f57890f7b7004b93361d69cd4b21079 + c32a7777a0f8f7a4fc8d9920d445f5f4b5658d38 - + https://github.com/dotnet/xharness - 31e0b8e08f57890f7b7004b93361d69cd4b21079 + c32a7777a0f8f7a4fc8d9920d445f5f4b5658d38 - + https://github.com/dotnet/xharness - 31e0b8e08f57890f7b7004b93361d69cd4b21079 + c32a7777a0f8f7a4fc8d9920d445f5f4b5658d38 https://github.com/dotnet/dotnet diff --git a/eng/pipelines/extra-platforms/runtime-extra-platforms-ioslike.yml b/eng/pipelines/extra-platforms/runtime-extra-platforms-ioslike.yml index da7fff53452b34..d5a9d77ac0b842 100644 --- a/eng/pipelines/extra-platforms/runtime-extra-platforms-ioslike.yml +++ b/eng/pipelines/extra-platforms/runtime-extra-platforms-ioslike.yml @@ -163,7 +163,7 @@ jobs: - template: /eng/pipelines/common/templates/runtimes/build-runtime-tests-and-send-to-helix.yml parameters: creator: dotnet-bot - testBuildArgs: tree nativeaot/SmokeTests /p:BuildNativeAOTRuntimePack=true + testBuildArgs: tree nativeaot/MobileSmokeTest /p:BuildNativeAOTRuntimePack=true testRunNamePrefixSuffix: NativeAOT_$(_BuildConfig) buildAllTestsAsStandalone: true diff --git a/eng/pipelines/extra-platforms/runtime-extra-platforms-ioslikesimulator.yml b/eng/pipelines/extra-platforms/runtime-extra-platforms-ioslikesimulator.yml index 9a5d8939d1f06a..f5044b5d50630f 100644 --- a/eng/pipelines/extra-platforms/runtime-extra-platforms-ioslikesimulator.yml +++ b/eng/pipelines/extra-platforms/runtime-extra-platforms-ioslikesimulator.yml @@ -130,7 +130,7 @@ jobs: - template: /eng/pipelines/common/templates/runtimes/build-runtime-tests-and-send-to-helix.yml parameters: creator: dotnet-bot - testBuildArgs: tree nativeaot/SmokeTests /p:BuildNativeAOTRuntimePack=true + testBuildArgs: tree nativeaot/MobileSmokeTest /p:BuildNativeAOTRuntimePack=true testRunNamePrefixSuffix: NativeAOT_$(_BuildConfig) buildAllTestsAsStandalone: true diff --git a/eng/pipelines/extra-platforms/runtime-extra-platforms-maccatalyst.yml b/eng/pipelines/extra-platforms/runtime-extra-platforms-maccatalyst.yml index cd2bba5421b151..92cba45048e616 100644 --- a/eng/pipelines/extra-platforms/runtime-extra-platforms-maccatalyst.yml +++ b/eng/pipelines/extra-platforms/runtime-extra-platforms-maccatalyst.yml @@ -162,7 +162,7 @@ jobs: parameters: creator: dotnet-bot buildAllTestsAsStandalone: true - testBuildArgs: tree nativeaot/SmokeTests /p:BuildNativeAOTRuntimePack=true + testBuildArgs: tree nativeaot/MobileSmokeTest /p:BuildNativeAOTRuntimePack=true testRunNamePrefixSuffix: NativeAOT_$(_BuildConfig) # @@ -201,7 +201,7 @@ jobs: parameters: creator: dotnet-bot buildAllTestsAsStandalone: true - testBuildArgs: tree nativeaot/SmokeTests /p:BuildNativeAOTRuntimePack=true /p:DevTeamProvisioning=adhoc /p:EnableAppSandbox=true + testBuildArgs: tree nativeaot/MobileSmokeTest /p:BuildNativeAOTRuntimePack=true /p:DevTeamProvisioning=adhoc /p:EnableAppSandbox=true testRunNamePrefixSuffix: NativeAOT_$(_BuildConfig) # diff --git a/eng/testing/BrowserVersions.props b/eng/testing/BrowserVersions.props index dd5f54e162bf27..0725d73db6ce2b 100644 --- a/eng/testing/BrowserVersions.props +++ b/eng/testing/BrowserVersions.props @@ -8,7 +8,7 @@ 1536371 https://storage.googleapis.com/chromium-browser-snapshots/Mac_Arm/1536376 14.3.127 - 146.0.7680.31 + 146.0.7680.66 1582197 https://storage.googleapis.com/chromium-browser-snapshots/Win_x64/1582218 14.6.202 diff --git a/src/coreclr/interpreter/compiler.cpp b/src/coreclr/interpreter/compiler.cpp index aa7282f0cbb3d4..10c649fa958f13 100644 --- a/src/coreclr/interpreter/compiler.cpp +++ b/src/coreclr/interpreter/compiler.cpp @@ -3096,7 +3096,6 @@ void InterpCompiler::EmitBinaryArithmeticOp(int32_t opBase) } else { -#if TARGET_64BIT if (type1 == StackTypeI8 && type2 == StackTypeI4) { EmitConv(m_pStackPointer - 1, StackTypeI8, InterpOpForWideningArgForImplicitUpcast((InterpOpcode)opBase)); @@ -3107,7 +3106,6 @@ void InterpCompiler::EmitBinaryArithmeticOp(int32_t opBase) EmitConv(m_pStackPointer - 2, StackTypeI8, InterpOpForWideningArgForImplicitUpcast((InterpOpcode)opBase)); type1 = StackTypeI8; } -#endif if (type1 == StackTypeR8 && type2 == StackTypeR4) { EmitConv(m_pStackPointer - 1, StackTypeR8, INTOP_CONV_R8_R4); diff --git a/src/coreclr/jit/codegen.h b/src/coreclr/jit/codegen.h index 8472dfe8c0233d..6b2ca6af8484d4 100644 --- a/src/coreclr/jit/codegen.h +++ b/src/coreclr/jit/codegen.h @@ -332,8 +332,11 @@ class CodeGen final : public CodeGenInterface // Prolog functions and data (there are a few exceptions for more generally used things) // - void genEstablishFramePointer(int delta, bool reportUnwindData); - void genHomeRegisterParams(regNumber initReg, bool* initRegStillZeroed); + void genEstablishFramePointer(int delta, bool reportUnwindData); + void genHomeRegisterParams(regNumber initReg, bool* initRegStillZeroed); +#ifdef TARGET_WASM + void genHomeRegisterParamsOutsideProlog(); +#endif regMaskTP genGetParameterHomingTempRegisterCandidates(); var_types genParamStackType(LclVarDsc* dsc, const ABIPassingSegment& seg); diff --git a/src/coreclr/jit/codegenlinear.cpp b/src/coreclr/jit/codegenlinear.cpp index 7823547e9edbe2..2be7f9c272edad 100644 --- a/src/coreclr/jit/codegenlinear.cpp +++ b/src/coreclr/jit/codegenlinear.cpp @@ -410,6 +410,16 @@ void CodeGen::genCodeForBBlist() } #endif +#ifdef TARGET_WASM + // genHomeRegisterParams can generate arbitrary amounts of code on Wasm, so + // we have moved it out of the prolog to the first basic block in order to + // work around the restriction that the prolog can only be one insGroup. + if (block->IsFirst()) + { + genHomeRegisterParamsOutsideProlog(); + } +#endif + #ifndef TARGET_WASM // TODO-WASM: enable genPoisonFrame // Emit poisoning into the init BB that comes right after prolog. // We cannot emit this code in the prolog as it might make the prolog too large. diff --git a/src/coreclr/jit/codegenloongarch64.cpp b/src/coreclr/jit/codegenloongarch64.cpp index feb4d28396a082..d64235083b03e9 100644 --- a/src/coreclr/jit/codegenloongarch64.cpp +++ b/src/coreclr/jit/codegenloongarch64.cpp @@ -557,14 +557,6 @@ void CodeGen::genCaptureFuncletPrologEpilogInfo() { delta_PSP -= TARGET_POINTER_SIZE; } - if ((m_compiler->lvaAsyncExecutionContextVar != BAD_VAR_NUM) && !m_compiler->opts.IsOSR()) - { - delta_PSP -= TARGET_POINTER_SIZE; - } - if ((m_compiler->lvaAsyncSynchronizationContextVar != BAD_VAR_NUM) && !m_compiler->opts.IsOSR()) - { - delta_PSP -= TARGET_POINTER_SIZE; - } funcletFrameSize = funcletFrameSize - delta_PSP; funcletFrameSize = roundUp((unsigned)funcletFrameSize, STACK_ALIGN); @@ -2279,7 +2271,7 @@ void CodeGen::genJumpTable(GenTree* treeNode) // Access to inline data is 'abstracted' by a special type of static member // (produced by eeFindJitDataOffs) which the emitter recognizes as being a reference // to constant data, not a real static field. - GetEmitter()->emitIns_R_C(INS_bl, emitActualTypeSize(TYP_I_IMPL), treeNode->GetRegNum(), REG_NA, + GetEmitter()->emitIns_R_C(INS_bl, EA_PTRSIZE, treeNode->GetRegNum(), REG_NA, m_compiler->eeFindJitDataOffs(jmpTabBase), 0); genProduceReg(treeNode); } @@ -2292,7 +2284,16 @@ void CodeGen::genJumpTable(GenTree* treeNode) // void CodeGen::genAsyncResumeInfo(GenTreeVal* treeNode) { - GetEmitter()->emitIns_R_C(INS_bl, emitActualTypeSize(TYP_I_IMPL), treeNode->GetRegNum(), REG_NA, + // INS_bl/b are placeholders that is not the final instruction. + instruction ins = INS_bl; + emitAttr attr = EA_PTRSIZE; + if (m_compiler->eeDataWithCodePointersNeedsRelocs()) + { + ins = INS_b; + attr = EA_SET_FLG(EA_PTRSIZE, EA_CNS_RELOC_FLG); + } + + GetEmitter()->emitIns_R_C(ins, attr, treeNode->GetRegNum(), REG_NA, genEmitAsyncResumeInfo((unsigned)treeNode->gtVal1), 0); genProduceReg(treeNode); } @@ -3341,8 +3342,17 @@ void CodeGen::genCodeForCompare(GenTreeOp* tree) } else { - emit->emitIns_I_la(EA_PTRSIZE, REG_RA, imm + 1); - emit->emitIns_R_R_R(IsUnsigned ? INS_sltu : INS_slt, EA_PTRSIZE, targetReg, regOp1, REG_RA); + assert(!(!IsUnsigned && (imm == INT64_MAX))); + if (IsUnsigned && (imm == ~0)) + { + // unsigned (a <= ~0) is always true. + emit->emitIns_R_R_I(INS_addi_d, EA_PTRSIZE, targetReg, REG_R0, 1); + } + else + { + emit->emitIns_I_la(EA_PTRSIZE, REG_RA, imm + 1); + emit->emitIns_R_R_R(IsUnsigned ? INS_sltu : INS_slt, EA_PTRSIZE, targetReg, regOp1, REG_RA); + } } } else if (tree->OperIs(GT_GT)) @@ -3711,14 +3721,6 @@ int CodeGenInterface::genSPtoFPdelta() const { delta -= TARGET_POINTER_SIZE; } - if ((m_compiler->lvaAsyncExecutionContextVar != BAD_VAR_NUM) && !m_compiler->opts.IsOSR()) - { - delta -= TARGET_POINTER_SIZE; - } - if ((m_compiler->lvaAsyncSynchronizationContextVar != BAD_VAR_NUM) && !m_compiler->opts.IsOSR()) - { - delta -= TARGET_POINTER_SIZE; - } assert(delta >= 0); return delta; @@ -6089,41 +6091,15 @@ void CodeGen::genCreateAndStoreGCInfo(unsigned codeSize, // Now we can actually use those slot ID's to declare live ranges. gcInfo.gcMakeRegPtrTable(gcInfoEncoder, codeSize, prologSize, GCInfo::MAKE_REG_PTR_MODE_DO_WORK, &callCnt); +#ifdef FEATURE_REMAP_FUNCTION if (m_compiler->opts.compDbgEnC) { - // what we have to preserve is called the "frame header" (see comments in VM\eetwain.cpp) - // which is: - // -return address - // -saved off RBP - // -saved 'this' pointer and bool for synchronized methods - - // 4 slots for RBP + return address + RSI + RDI - int preservedAreaSize = 4 * REGSIZE_BYTES; - - if (m_compiler->info.compFlags & CORINFO_FLG_SYNCH) - { - if (!(m_compiler->info.compFlags & CORINFO_FLG_STATIC)) - { - preservedAreaSize += REGSIZE_BYTES; - } - - preservedAreaSize += 1; // bool for synchronized methods - } - - if (m_compiler->lvaAsyncExecutionContextVar != BAD_VAR_NUM) - { - preservedAreaSize += TARGET_POINTER_SIZE; - } - - if (m_compiler->lvaAsyncSynchronizationContextVar != BAD_VAR_NUM) - { - preservedAreaSize += TARGET_POINTER_SIZE; - } - - // Used to signal both that the method is compiled for EnC, and also the size of the block at the top of the - // frame - gcInfoEncoder->SetSizeOfEditAndContinuePreservedArea(preservedAreaSize); + // TODO: lvaMonAcquired, lvaAsyncExecutionContextVar and lvaAsyncExecutionContextVar locals are special + // that is necessary to allocate in the top of the stack frame and included as part of the EnC frame header + // for EnC to work. + NYI_LOONGARCH64("compDbgEnc in CodeGen::genCreateAndStoreGCInfo() ---unimplemented/unused on LA64 yet---"); } +#endif // FEATURE_REMAP_FUNCTION if (m_compiler->opts.IsReversePInvoke()) { @@ -6765,14 +6741,6 @@ void CodeGen::genPushCalleeSavedRegisters(regNumber initReg, bool* pInitRegZeroe { localFrameSize -= TARGET_POINTER_SIZE; } - if ((m_compiler->lvaAsyncExecutionContextVar != BAD_VAR_NUM) && !m_compiler->opts.IsOSR()) - { - localFrameSize -= TARGET_POINTER_SIZE; - } - if ((m_compiler->lvaAsyncSynchronizationContextVar != BAD_VAR_NUM) && !m_compiler->opts.IsOSR()) - { - localFrameSize -= TARGET_POINTER_SIZE; - } #ifdef DEBUG if (m_compiler->opts.disAsm) @@ -6839,14 +6807,6 @@ void CodeGen::genPopCalleeSavedRegisters(bool jmpEpilog) { localFrameSize -= TARGET_POINTER_SIZE; } - if ((m_compiler->lvaAsyncExecutionContextVar != BAD_VAR_NUM) && !m_compiler->opts.IsOSR()) - { - localFrameSize -= TARGET_POINTER_SIZE; - } - if ((m_compiler->lvaAsyncSynchronizationContextVar != BAD_VAR_NUM) && !m_compiler->opts.IsOSR()) - { - localFrameSize -= TARGET_POINTER_SIZE; - } JITDUMP("Frame type. #outsz=%d; #framesz=%d; #calleeSaveRegsPushed:%d; " "localloc? %s\n", diff --git a/src/coreclr/jit/codegenwasm.cpp b/src/coreclr/jit/codegenwasm.cpp index 4dc8af8418ac9b..32f5ef4cdb950b 100644 --- a/src/coreclr/jit/codegenwasm.cpp +++ b/src/coreclr/jit/codegenwasm.cpp @@ -121,6 +121,22 @@ void CodeGen::genEnregisterOSRArgsAndLocals() //------------------------------------------------------------------------ // genHomeRegisterParams: place register arguments into their RA-assigned locations. // +// We can't actually do this task here because the prolog will overflow. Instead, we +// do this later on and inject all the relevant code into the first basic block. +// See genHomeRegisterParamsOutsideProlog, below. +// +// Arguments: +// initReg - Unused +// initRegStillZeroed - Unused +// +void CodeGen::genHomeRegisterParams(regNumber initReg, bool* initRegStillZeroed) +{ + // Intentionally empty +} + +//------------------------------------------------------------------------ +// genHomeRegisterParamsOutsideProlog: place register arguments into their RA-assigned locations. +// // For the WASM RA, we have a much simplified (compared to LSRA) contract of: // - If an argument is live on entry in a set of registers, then the RA will // assign those registers to that argument on entry. @@ -129,14 +145,9 @@ void CodeGen::genEnregisterOSRArgsAndLocals() // The main motivation for this (along with the obvious CQ implications) is // obviating the need to adapt the general "RegGraph"-based algorithm to // !HAS_FIXED_REGISTER_SET constraints (no reg masks). -// -// Arguments: -// initReg - Unused -// initRegStillZeroed - Unused -// -void CodeGen::genHomeRegisterParams(regNumber initReg, bool* initRegStillZeroed) +void CodeGen::genHomeRegisterParamsOutsideProlog() { - JITDUMP("*************** In genHomeRegisterParams()\n"); + JITDUMP("*************** In genHomeRegisterParamsOutsideProlog()\n"); auto spillParam = [this](unsigned lclNum, unsigned offset, unsigned paramLclNum, const ABIPassingSegment& segment) { assert(segment.IsPassedInRegister()); diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index d9e256c164e345..cedc714d270ec9 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -4210,6 +4210,17 @@ class Compiler unsigned lvaLclExactSize(unsigned varNum); ValueSize lvaLclValueSize(unsigned varNum); + //----------------------------------------------------------------------------- + // lvaIsUnknownSizeLocal: Does the local have an unknown size at compile-time? + // + // Returns: + // True if the local does not have an exact size, else false. + // + bool lvaIsUnknownSizeLocal(unsigned varNum) + { + return !lvaLclValueSize(varNum).IsExact(); + } + bool lvaHaveManyLocals(float percent = 1.0f) const; unsigned lvaGrabTemp(bool shortLifetime DEBUGARG(const char* reason)); @@ -6878,6 +6889,8 @@ class Compiler public: bool fgIsBigOffset(size_t offset); bool IsValidLclAddr(unsigned lclNum, unsigned offset); + bool IsEntireAccess(unsigned lclNum, unsigned offset, ValueSize accessSize); + bool IsWideAccess(unsigned lclNum, unsigned offset, ValueSize accessSize); bool IsPotentialGCSafePoint(GenTree* tree) const; private: diff --git a/src/coreclr/jit/compiler.hpp b/src/coreclr/jit/compiler.hpp index 2a618c5c2f1232..4484a8ae95075c 100644 --- a/src/coreclr/jit/compiler.hpp +++ b/src/coreclr/jit/compiler.hpp @@ -3324,7 +3324,7 @@ inline bool Compiler::fgIsBigOffset(size_t offset) } //------------------------------------------------------------------------ -// IsValidLclAddr: Can the given local address be represented as "LCL_FLD_ADDR"? +// IsValidLclAddr: Can the given local address be represented as "LCL_ADDR"? // // Local address nodes cannot point beyond the local and can only store // 16 bits worth of offset. @@ -3334,19 +3334,72 @@ inline bool Compiler::fgIsBigOffset(size_t offset) // offset - The address' offset // // Return Value: -// Whether "LCL_FLD_ADDR [+offset]" would be valid IR. +// Whether "LCL_ADDR [+offset]" would be valid IR. // inline bool Compiler::IsValidLclAddr(unsigned lclNum, unsigned offset) { #ifdef TARGET_ARM64 - if (varTypeHasUnknownSize(lvaGetDesc(lclNum))) + if (lvaIsUnknownSizeLocal(lclNum)) { - return false; + return (offset == 0); } #endif return (offset < UINT16_MAX) && (offset < lvaLclExactSize(lclNum)); } +//------------------------------------------------------------------------ +// IsEntireAccess: Is the access to a local entire? +// +// The access is entire when the size of the access is equivalent to the size +// of the local, and the access address is equivalent to the local address +// (offset == 0). +// +// Arguments: +// lclNum - The local's number +// offset - The access offset +// accessSize - The size of the access (may be unknown at compile-time) +// +// Return Value: +// True is the access is entire by the definition above, else false. +// +inline bool Compiler::IsEntireAccess(unsigned lclNum, unsigned offset, ValueSize accessSize) +{ + return (lvaLclValueSize(lclNum) == accessSize) && (offset == 0); +} + +//------------------------------------------------------------------------ +// IsWideAccess: Is the access to a local wide? +// +// An access is wide when the access overflows the end of the local. If the +// access size is unknown, the access is assumed wide if it is not entire. +// +// Arguments: +// lclNum - The local's number +// offset - The access offset +// accessSize - The size of the access (may be unknown at compile-time) +// +// Return Value: +// True is the access is wide by the definition above, else false. +// +inline bool Compiler::IsWideAccess(unsigned lclNum, unsigned offset, ValueSize accessSize) +{ + assert(!accessSize.IsNull()); + if (accessSize.IsExact()) + { + ClrSafeInt extent = ClrSafeInt(offset) + ClrSafeInt(accessSize.GetExact()); + // The access is wide if: + // * The offset computation overflows uint16_t. + // * The address at `offset + accessSize - 1`, (the last byte of the access) is out of bounds of the local. + return extent.IsOverflow() || !FitsIn(extent.Value()) || !IsValidLclAddr(lclNum, extent.Value() - 1); + } + else + { + // If we don't know the size of the access or the local at compile time, we assume any access overflows if + // it is not an entire access to the local. + return !IsEntireAccess(lclNum, offset, accessSize); + } +} + //------------------------------------------------------------------------ // IsPotentialGCSafePoint: Can the given tree be effectively a gc safe point? // diff --git a/src/coreclr/jit/emit.cpp b/src/coreclr/jit/emit.cpp index 3eafb5c5bc9344..e620d149ca10b6 100644 --- a/src/coreclr/jit/emit.cpp +++ b/src/coreclr/jit/emit.cpp @@ -9765,7 +9765,8 @@ insGroup* emitter::emitAllocIG() ig = (insGroup*)emitGetMem(sz); #ifdef DEBUG - ig->igSelf = ig; + ig->igSelf = ig; + ig->igDataSize = 0; #endif #if EMITTER_STATS @@ -9832,6 +9833,8 @@ void emitter::emitInitIG(insGroup* ig) // Explicitly call init, since IGs don't actually have a constructor. ig->igBlocks.jitstd::list::init(m_compiler->getAllocator(CMK_DebugOnly)); #endif + + ig->igData = nullptr; } /***************************************************************************** diff --git a/src/coreclr/jit/emitloongarch64.cpp b/src/coreclr/jit/emitloongarch64.cpp index 83d6425480678e..6f752c830ba97f 100644 --- a/src/coreclr/jit/emitloongarch64.cpp +++ b/src/coreclr/jit/emitloongarch64.cpp @@ -1972,8 +1972,8 @@ void emitter::emitIns_R_R_R_R( /***************************************************************************** * * Add an instruction with a register + static member operands. - * Constant is stored into JIT data which is adjacent to code. - * For LOONGARCH64, maybe not the best, here just supports the func-interface. + * Usually constants are stored into JIT data adjacent to code, in which case no + * relocation is needed. PC-relative offset will be encoded directly into instruction. * */ void emitter::emitIns_R_C( @@ -1982,10 +1982,13 @@ void emitter::emitIns_R_C( assert(offs >= 0); assert(instrDesc::fitsInSmallCns(offs)); // can optimize. - // when id->idIns == bl, for reloc! 4-ins. + // when id->idIns == b, for AsyncResumeInfo reloc. + // pcalau12i reg, off-hi-20bits + // addi_d reg, offs_lo-12bits(reg) + // when id->idIns == bl, for reloc! 2-ins. // pcaddu12i reg, off-hi-20bits // addi_d reg, reg, off-lo-12bits - // when id->idIns == load-ins, for reloc! 4-ins. + // when id->idIns == load-ins, for reloc! 2-ins. // pcaddu12i reg, off-hi-20bits // load reg, offs_lo-12bits(reg) // @@ -2000,6 +2003,7 @@ void emitter::emitIns_R_C( // load reg, r21 + addr_bits[11:0] instrDesc* id = emitNewInstr(attr); + id->idSetRelocFlags(attr); id->idIns(ins); assert(reg != REG_R0); // for special. reg Must not be R0. @@ -2007,7 +2011,7 @@ void emitter::emitIns_R_C( id->idSmallCns(offs); // usually is 0. id->idInsOpt(INS_OPTS_RC); - if (m_compiler->opts.compReloc) + if (m_compiler->opts.compReloc || id->idIsReloc()) { id->idSetIsDspReloc(); id->idCodeSize(8); @@ -2030,7 +2034,6 @@ void emitter::emitIns_R_C( id->idOpSize(EA_PTRSIZE); } - // TODO-LoongArch64: this maybe deleted. id->idSetIsBound(); // We won't patch address since we will know the exact distance // once JIT code and data are allocated together. @@ -3376,6 +3379,9 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp) { // Reference to JIT data + // when id->idIns == b, for AsyncResumeInfo reloc. + // pcalau12i reg, off-hi-20bits + // addi_d reg, offs_lo-12bits(reg) // when id->idIns == bl, for reloc! // pcaddu12i r21, off-hi-20bits // addi_d reg, r21, off-lo-12bits @@ -3408,7 +3414,18 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp) ins = id->idIns(); regNumber reg1 = id->idReg1(); - if (id->idIsReloc()) + if (ins == INS_b) + { + // relocation for AsyncResumeInfo. + *(code_t*)dstRW = 0x1a000000 | (code_t)reg1; + dstRW += 4; + ins = INS_addi_d; + *(code_t*)dstRW = 0x02c00000 | (code_t)reg1 | (code_t)(reg1 << 5); + dstRW += 4; + emitRecordRelocation(dstRW - 8 - writeableOffset, emitDataOffsetToPtr(dataOffs), + CorInfoReloc::LOONGARCH64_PC); + } + else if (id->idIsReloc()) { // get the addr-offset of the data. imm = (ssize_t)emitDataOffsetToPtr(dataOffs) - (ssize_t)(dstRW - writeableOffset); diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 5a65ddcadf0943..3dfca0ba725a0a 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -7358,9 +7358,6 @@ ExceptionSetFlags GenTree::OperExceptions(Compiler* comp) case GT_CKFINITE: return ExceptionSetFlags::ArithmeticException; - case GT_LCLHEAP: - return ExceptionSetFlags::StackOverflowException; - #ifdef FEATURE_HW_INTRINSICS case GT_HWINTRINSIC: { @@ -28370,8 +28367,8 @@ bool GenTreeHWIntrinsic::OperIsMemoryLoad(GenTree** pAddr) const case NI_Sve_GatherVectorUInt32WithByteOffsetsZeroExtendFirstFaulting: case NI_Sve_GatherVectorUInt32ZeroExtend: case NI_Sve_GatherVectorUInt32ZeroExtendFirstFaulting: - case NI_Sve_GatherVectorWithByteOffsetFirstFaulting: case NI_Sve_GatherVectorWithByteOffsets: + case NI_Sve_GatherVectorWithByteOffsetFirstFaulting: case NI_Sve_LoadVector: case NI_Sve_LoadVectorNonTemporal: case NI_Sve_LoadVector128AndReplicateToVector: @@ -28434,6 +28431,18 @@ bool GenTreeHWIntrinsic::OperIsMemoryLoad(GenTree** pAddr) const case NI_Sve_LoadVectorUInt16NonFaultingZeroExtendToUInt64: case NI_Sve_LoadVectorUInt32NonFaultingZeroExtendToInt64: case NI_Sve_LoadVectorUInt32NonFaultingZeroExtendToUInt64: + case NI_Sve2_GatherVectorByteZeroExtendNonTemporal: + case NI_Sve2_GatherVectorInt16SignExtendNonTemporal: + case NI_Sve2_GatherVectorInt16WithByteOffsetsSignExtendNonTemporal: + case NI_Sve2_GatherVectorInt32SignExtendNonTemporal: + case NI_Sve2_GatherVectorInt32WithByteOffsetsSignExtendNonTemporal: + case NI_Sve2_GatherVectorNonTemporal: + case NI_Sve2_GatherVectorSByteSignExtendNonTemporal: + case NI_Sve2_GatherVectorUInt16WithByteOffsetsZeroExtendNonTemporal: + case NI_Sve2_GatherVectorUInt16ZeroExtendNonTemporal: + case NI_Sve2_GatherVectorUInt32WithByteOffsetsZeroExtendNonTemporal: + case NI_Sve2_GatherVectorUInt32ZeroExtendNonTemporal: + case NI_Sve2_GatherVectorWithByteOffsetsNonTemporal: addr = Op(2); break; @@ -28526,9 +28535,24 @@ bool GenTreeHWIntrinsic::OperIsMemoryLoad(GenTree** pAddr) const NI_Sve_GatherVectorUInt32WithByteOffsetsZeroExtend, NI_Sve_GatherVectorUInt32WithByteOffsetsZeroExtendFirstFaulting, NI_Sve_GatherVectorUInt32ZeroExtend, NI_Sve_GatherVectorUInt32ZeroExtendFirstFaulting)); - assert(varTypeIsI(addr) || - (varTypeIsSIMD(addr) && ((intrinsicId >= NI_Sve_GatherVector) && - (intrinsicId <= NI_Sve_GatherVectorUInt32ZeroExtendFirstFaulting)))); + + static_assert(AreContiguous(NI_Sve2_GatherVectorByteZeroExtendNonTemporal, + NI_Sve2_GatherVectorInt16SignExtendNonTemporal, + NI_Sve2_GatherVectorInt16WithByteOffsetsSignExtendNonTemporal, + NI_Sve2_GatherVectorInt32SignExtendNonTemporal, + NI_Sve2_GatherVectorInt32WithByteOffsetsSignExtendNonTemporal, + NI_Sve2_GatherVectorNonTemporal, NI_Sve2_GatherVectorSByteSignExtendNonTemporal, + NI_Sve2_GatherVectorUInt16WithByteOffsetsZeroExtendNonTemporal, + NI_Sve2_GatherVectorUInt16ZeroExtendNonTemporal, + NI_Sve2_GatherVectorUInt32WithByteOffsetsZeroExtendNonTemporal, + NI_Sve2_GatherVectorUInt32ZeroExtendNonTemporal, + NI_Sve2_GatherVectorWithByteOffsetsNonTemporal)); + + bool isSveGatherLoad = + (intrinsicId >= NI_Sve_GatherVector) && (intrinsicId <= NI_Sve_GatherVectorUInt32ZeroExtendFirstFaulting); + bool isSve2GatherLoad = (intrinsicId >= NI_Sve2_GatherVectorByteZeroExtendNonTemporal) && + (intrinsicId <= NI_Sve2_GatherVectorWithByteOffsetsNonTemporal); + assert(varTypeIsI(addr) || (varTypeIsSIMD(addr) && (isSveGatherLoad || isSve2GatherLoad))); #else assert(varTypeIsI(addr)); #endif diff --git a/src/coreclr/jit/hwintrinsic.cpp b/src/coreclr/jit/hwintrinsic.cpp index 406e6a1369aeeb..1a59fbc869bab2 100644 --- a/src/coreclr/jit/hwintrinsic.cpp +++ b/src/coreclr/jit/hwintrinsic.cpp @@ -2490,9 +2490,21 @@ GenTree* Compiler::impHWIntrinsic(NamedIntrinsic intrinsic, case NI_Sve_GatherVectorUInt32WithByteOffsetsZeroExtend: case NI_Sve_GatherVectorUInt32WithByteOffsetsZeroExtendFirstFaulting: case NI_Sve_GatherVectorUInt32ZeroExtend: - case NI_Sve_GatherVectorWithByteOffsetFirstFaulting: - case NI_Sve_GatherVectorWithByteOffsets: case NI_Sve_GatherVectorUInt32ZeroExtendFirstFaulting: + case NI_Sve_GatherVectorWithByteOffsets: + case NI_Sve_GatherVectorWithByteOffsetFirstFaulting: + case NI_Sve2_GatherVectorByteZeroExtendNonTemporal: + case NI_Sve2_GatherVectorInt16SignExtendNonTemporal: + case NI_Sve2_GatherVectorInt16WithByteOffsetsSignExtendNonTemporal: + case NI_Sve2_GatherVectorInt32SignExtendNonTemporal: + case NI_Sve2_GatherVectorInt32WithByteOffsetsSignExtendNonTemporal: + case NI_Sve2_GatherVectorNonTemporal: + case NI_Sve2_GatherVectorSByteSignExtendNonTemporal: + case NI_Sve2_GatherVectorUInt16WithByteOffsetsZeroExtendNonTemporal: + case NI_Sve2_GatherVectorUInt16ZeroExtendNonTemporal: + case NI_Sve2_GatherVectorUInt32WithByteOffsetsZeroExtendNonTemporal: + case NI_Sve2_GatherVectorUInt32ZeroExtendNonTemporal: + case NI_Sve2_GatherVectorWithByteOffsetsNonTemporal: assert(varTypeIsSIMD(op3->TypeGet())); if (numArgs == 3) { diff --git a/src/coreclr/jit/hwintrinsiccodegenarm64.cpp b/src/coreclr/jit/hwintrinsiccodegenarm64.cpp index 9016b8a91b2fd3..cb446cba8fcdc0 100644 --- a/src/coreclr/jit/hwintrinsiccodegenarm64.cpp +++ b/src/coreclr/jit/hwintrinsiccodegenarm64.cpp @@ -2368,6 +2368,79 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) break; } + case NI_Sve2_GatherVectorInt16SignExtendNonTemporal: + case NI_Sve2_GatherVectorInt32SignExtendNonTemporal: + case NI_Sve2_GatherVectorNonTemporal: + case NI_Sve2_GatherVectorUInt16ZeroExtendNonTemporal: + case NI_Sve2_GatherVectorUInt32ZeroExtendNonTemporal: + { + if (!varTypeIsSIMD(intrin.op2->gtType)) + { + // GatherVector...(Vector mask, T* address, Vector indices) + + assert(intrin.numOperands == 3); + + ssize_t shift = 0; + regNumber tempReg = internalRegisters.GetSingle(node, RBM_ALLFLOAT); + + if ((intrin.id == NI_Sve2_GatherVectorInt16SignExtendNonTemporal) || + (intrin.id == NI_Sve2_GatherVectorUInt16ZeroExtendNonTemporal)) + { + shift = 1; + } + else if ((intrin.id == NI_Sve2_GatherVectorInt32SignExtendNonTemporal) || + (intrin.id == NI_Sve2_GatherVectorUInt32ZeroExtendNonTemporal)) + { + shift = 2; + } + else + { + assert(intrin.id == NI_Sve2_GatherVectorNonTemporal); + assert(emitActualTypeSize(intrin.baseType) == EA_8BYTE); + shift = 3; + } + + // The SVE2 instructions only support byte offsets. Convert indices to bytes. + GetEmitter()->emitIns_R_R_I(INS_sve_lsl, emitSize, tempReg, op3Reg, shift, opt); + + GetEmitter()->emitIns_R_R_R_R(ins, emitSize, targetReg, op1Reg, tempReg, op2Reg, opt); + } + else + { + // GatherVector...(Vector mask, Vector addresses) + assert(intrin.numOperands == 2); + GetEmitter()->emitIns_R_R_R_R(ins, emitSize, targetReg, op1Reg, op2Reg, REG_ZR, opt); + } + break; + } + + case NI_Sve2_GatherVectorByteZeroExtendNonTemporal: + case NI_Sve2_GatherVectorSByteSignExtendNonTemporal: + if (!varTypeIsSIMD(intrin.op2->gtType)) + { + // GatherVector...(Vector mask, T* address, Vector offsets) + assert(intrin.numOperands == 3); + GetEmitter()->emitIns_R_R_R_R(ins, emitSize, targetReg, op1Reg, op3Reg, op2Reg, opt); + } + else + { + // GatherVector...(Vector mask, Vector addresses) + assert(intrin.numOperands == 2); + GetEmitter()->emitIns_R_R_R_R(ins, emitSize, targetReg, op1Reg, op2Reg, REG_ZR, opt); + } + break; + + case NI_Sve2_GatherVectorInt16WithByteOffsetsSignExtendNonTemporal: + case NI_Sve2_GatherVectorInt32WithByteOffsetsSignExtendNonTemporal: + case NI_Sve2_GatherVectorUInt16WithByteOffsetsZeroExtendNonTemporal: + case NI_Sve2_GatherVectorUInt32WithByteOffsetsZeroExtendNonTemporal: + case NI_Sve2_GatherVectorWithByteOffsetsNonTemporal: + // GatherVector...(Vector mask, T* address, Vector offsets) + assert(!varTypeIsSIMD(intrin.op2->gtType)); + assert(intrin.numOperands == 3); + GetEmitter()->emitIns_R_R_R_R(ins, emitSize, targetReg, op1Reg, op3Reg, op2Reg, opt); + break; + case NI_Sve_ReverseElement: // Use non-predicated version explicitly GetEmitter()->emitIns_R_R(ins, emitSize, targetReg, op1Reg, opt); diff --git a/src/coreclr/jit/hwintrinsiclistarm64sve.h b/src/coreclr/jit/hwintrinsiclistarm64sve.h index 2bd17aab0f61da..06ddd231b5ed74 100644 --- a/src/coreclr/jit/hwintrinsiclistarm64sve.h +++ b/src/coreclr/jit/hwintrinsiclistarm64sve.h @@ -131,10 +131,10 @@ HARDWARE_INTRINSIC(Sve, GatherVectorUInt16WithByteOffsetsZeroExtend, HARDWARE_INTRINSIC(Sve, GatherVectorUInt16WithByteOffsetsZeroExtendFirstFaulting, -1, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ldff1h, INS_sve_ldff1h, INS_sve_ldff1h, INS_sve_ldff1h, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_SpecialCodeGen|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation|HW_Flag_ZeroingMaskedOperation|HW_Flag_SpecialSideEffect_Other) HARDWARE_INTRINSIC(Sve, GatherVectorUInt16ZeroExtend, -1, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ld1h, INS_sve_ld1h, INS_sve_ld1h, INS_sve_ld1h, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_SpecialCodeGen|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation|HW_Flag_ZeroingMaskedOperation) HARDWARE_INTRINSIC(Sve, GatherVectorUInt16ZeroExtendFirstFaulting, -1, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ldff1h, INS_sve_ldff1h, INS_sve_ldff1h, INS_sve_ldff1h, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_SpecialCodeGen|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation|HW_Flag_ZeroingMaskedOperation|HW_Flag_SpecialSideEffect_Other) -HARDWARE_INTRINSIC(Sve, GatherVectorUInt32WithByteOffsetsZeroExtend, -1, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ld1w, INS_sve_ld1w, INS_sve_ld1w, INS_sve_ld1w, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_SpecialCodeGen|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation|HW_Flag_ZeroingMaskedOperation) -HARDWARE_INTRINSIC(Sve, GatherVectorUInt32WithByteOffsetsZeroExtendFirstFaulting, -1, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ldff1w, INS_sve_ldff1w, INS_sve_ldff1w, INS_sve_ldff1w, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_SpecialCodeGen|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation|HW_Flag_ZeroingMaskedOperation|HW_Flag_SpecialSideEffect_Other) -HARDWARE_INTRINSIC(Sve, GatherVectorUInt32ZeroExtend, -1, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ld1w, INS_sve_ld1w, INS_sve_ld1w, INS_sve_ld1w, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_SpecialCodeGen|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation|HW_Flag_ZeroingMaskedOperation) -HARDWARE_INTRINSIC(Sve, GatherVectorUInt32ZeroExtendFirstFaulting, -1, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ldff1w, INS_sve_ldff1w, INS_sve_ldff1w, INS_sve_ldff1w, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_SpecialCodeGen|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation|HW_Flag_ZeroingMaskedOperation|HW_Flag_SpecialSideEffect_Other) +HARDWARE_INTRINSIC(Sve, GatherVectorUInt32WithByteOffsetsZeroExtend, -1, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ld1w, INS_sve_ld1w, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_SpecialCodeGen|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation|HW_Flag_ZeroingMaskedOperation) +HARDWARE_INTRINSIC(Sve, GatherVectorUInt32WithByteOffsetsZeroExtendFirstFaulting, -1, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ldff1w, INS_sve_ldff1w, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_SpecialCodeGen|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation|HW_Flag_ZeroingMaskedOperation|HW_Flag_SpecialSideEffect_Other) +HARDWARE_INTRINSIC(Sve, GatherVectorUInt32ZeroExtend, -1, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ld1w, INS_sve_ld1w, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_SpecialCodeGen|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation|HW_Flag_ZeroingMaskedOperation) +HARDWARE_INTRINSIC(Sve, GatherVectorUInt32ZeroExtendFirstFaulting, -1, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ldff1w, INS_sve_ldff1w, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_SpecialCodeGen|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation|HW_Flag_ZeroingMaskedOperation|HW_Flag_SpecialSideEffect_Other) HARDWARE_INTRINSIC(Sve, GatherVectorWithByteOffsetFirstFaulting, -1, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ldff1w, INS_sve_ldff1w, INS_sve_ldff1d, INS_sve_ldff1d, INS_sve_ldff1w, INS_sve_ldff1d}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_SpecialCodeGen|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation|HW_Flag_ZeroingMaskedOperation|HW_Flag_SpecialSideEffect_Other) HARDWARE_INTRINSIC(Sve, GatherVectorWithByteOffsets, -1, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ld1w, INS_sve_ld1w, INS_sve_ld1d, INS_sve_ld1d, INS_sve_ld1w, INS_sve_ld1d}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_SpecialCodeGen|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation|HW_Flag_ZeroingMaskedOperation) HARDWARE_INTRINSIC(Sve, GetActiveElementCount, -1, 2, {INS_sve_cntp, INS_sve_cntp, INS_sve_cntp, INS_sve_cntp, INS_sve_cntp, INS_sve_cntp, INS_sve_cntp, INS_sve_cntp, INS_sve_cntp, INS_sve_cntp}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_BaseTypeFromFirstArg|HW_Flag_ExplicitMaskedOperation) @@ -351,6 +351,18 @@ HARDWARE_INTRINSIC(Sve2, DotProductRotateComplexBySelectedIndex, HARDWARE_INTRINSIC(Sve2, FusedAddHalving, -1, -1, {INS_sve_shadd, INS_sve_uhadd, INS_sve_shadd, INS_sve_uhadd, INS_sve_shadd, INS_sve_uhadd, INS_sve_shadd, INS_sve_uhadd, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_EmbeddedMaskedOperation|HW_Flag_HasRMWSemantics|HW_Flag_LowMaskedOperation) HARDWARE_INTRINSIC(Sve2, FusedAddRoundedHalving, -1, -1, {INS_sve_srhadd, INS_sve_urhadd, INS_sve_srhadd, INS_sve_urhadd, INS_sve_srhadd, INS_sve_urhadd, INS_sve_srhadd, INS_sve_urhadd, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_EmbeddedMaskedOperation|HW_Flag_HasRMWSemantics|HW_Flag_LowMaskedOperation) HARDWARE_INTRINSIC(Sve2, FusedSubtractHalving, -1, -1, {INS_sve_shsub, INS_sve_uhsub, INS_sve_shsub, INS_sve_uhsub, INS_sve_shsub, INS_sve_uhsub, INS_sve_shsub, INS_sve_uhsub, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_EmbeddedMaskedOperation|HW_Flag_HasRMWSemantics|HW_Flag_LowMaskedOperation) +HARDWARE_INTRINSIC(Sve2, GatherVectorByteZeroExtendNonTemporal, -1, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ldnt1b, INS_sve_ldnt1b, INS_sve_ldnt1b, INS_sve_ldnt1b, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_SpecialCodeGen|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation|HW_Flag_ZeroingMaskedOperation) +HARDWARE_INTRINSIC(Sve2, GatherVectorInt16SignExtendNonTemporal, -1, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ldnt1sh, INS_sve_ldnt1sh, INS_sve_ldnt1sh, INS_sve_ldnt1sh, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_SpecialCodeGen|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation|HW_Flag_ZeroingMaskedOperation) +HARDWARE_INTRINSIC(Sve2, GatherVectorInt16WithByteOffsetsSignExtendNonTemporal, -1, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ldnt1sh, INS_sve_ldnt1sh, INS_sve_ldnt1sh, INS_sve_ldnt1sh, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_SpecialCodeGen|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation|HW_Flag_ZeroingMaskedOperation) +HARDWARE_INTRINSIC(Sve2, GatherVectorInt32SignExtendNonTemporal, -1, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ldnt1sw, INS_sve_ldnt1sw, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_SpecialCodeGen|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation|HW_Flag_ZeroingMaskedOperation) +HARDWARE_INTRINSIC(Sve2, GatherVectorInt32WithByteOffsetsSignExtendNonTemporal, -1, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ldnt1sw, INS_sve_ldnt1sw, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_SpecialCodeGen|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation|HW_Flag_ZeroingMaskedOperation) +HARDWARE_INTRINSIC(Sve2, GatherVectorNonTemporal, -1, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ldnt1w, INS_sve_ldnt1w, INS_sve_ldnt1d, INS_sve_ldnt1d, INS_sve_ldnt1w, INS_sve_ldnt1d}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_SpecialCodeGen|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation|HW_Flag_ZeroingMaskedOperation) +HARDWARE_INTRINSIC(Sve2, GatherVectorSByteSignExtendNonTemporal, -1, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ldnt1sb, INS_sve_ldnt1sb, INS_sve_ldnt1sb, INS_sve_ldnt1sb, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_SpecialCodeGen|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation|HW_Flag_ZeroingMaskedOperation) +HARDWARE_INTRINSIC(Sve2, GatherVectorUInt16WithByteOffsetsZeroExtendNonTemporal, -1, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ldnt1h, INS_sve_ldnt1h, INS_sve_ldnt1h, INS_sve_ldnt1h, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_SpecialCodeGen|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation|HW_Flag_ZeroingMaskedOperation) +HARDWARE_INTRINSIC(Sve2, GatherVectorUInt16ZeroExtendNonTemporal, -1, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ldnt1h, INS_sve_ldnt1h, INS_sve_ldnt1h, INS_sve_ldnt1h, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_SpecialCodeGen|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation|HW_Flag_ZeroingMaskedOperation) +HARDWARE_INTRINSIC(Sve2, GatherVectorUInt32WithByteOffsetsZeroExtendNonTemporal, -1, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ldnt1w, INS_sve_ldnt1w, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_SpecialCodeGen|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation|HW_Flag_ZeroingMaskedOperation) +HARDWARE_INTRINSIC(Sve2, GatherVectorUInt32ZeroExtendNonTemporal, -1, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ldnt1w, INS_sve_ldnt1w, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_SpecialCodeGen|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation|HW_Flag_ZeroingMaskedOperation) +HARDWARE_INTRINSIC(Sve2, GatherVectorWithByteOffsetsNonTemporal, -1, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ldnt1w, INS_sve_ldnt1w, INS_sve_ldnt1d, INS_sve_ldnt1d, INS_sve_ldnt1w, INS_sve_ldnt1d}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_SpecialCodeGen|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation|HW_Flag_ZeroingMaskedOperation) HARDWARE_INTRINSIC(Sve2, InterleavingXorEvenOdd, -1, 3, {INS_sve_eorbt, INS_sve_eorbt, INS_sve_eorbt, INS_sve_eorbt, INS_sve_eorbt, INS_sve_eorbt, INS_sve_eorbt, INS_sve_eorbt, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_HasRMWSemantics) HARDWARE_INTRINSIC(Sve2, InterleavingXorOddEven, -1, 3, {INS_sve_eortb, INS_sve_eortb, INS_sve_eortb, INS_sve_eortb, INS_sve_eortb, INS_sve_eortb, INS_sve_eortb, INS_sve_eortb, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_HasRMWSemantics) HARDWARE_INTRINSIC(Sve2, Log2, -1, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_flogb, INS_invalid, INS_sve_flogb, INS_invalid, INS_sve_flogb, INS_sve_flogb}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_BaseTypeFromFirstArg|HW_Flag_EmbeddedMaskedOperation|HW_Flag_LowMaskedOperation) diff --git a/src/coreclr/jit/ifconversion.cpp b/src/coreclr/jit/ifconversion.cpp index 1b49c438aab9ad..0b9e11c962e8fb 100644 --- a/src/coreclr/jit/ifconversion.cpp +++ b/src/coreclr/jit/ifconversion.cpp @@ -55,7 +55,6 @@ class OptIfConversionDsc bool IfConvertCheckThenFlow(); void IfConvertFindFlow(); bool IfConvertCheckStmts(BasicBlock* fromBlock, IfConvertOperation* foundOperation); - void IfConvertJoinStmts(BasicBlock* fromBlock); GenTree* TryTransformSelectOperOrLocal(GenTree* oper, GenTree* lcl); GenTree* TryTransformSelectOperOrZero(GenTree* oper, GenTree* lcl); @@ -356,26 +355,6 @@ bool OptIfConversionDsc::IfConvertCheckStmts(BasicBlock* fromBlock, IfConvertOpe return found; } -//----------------------------------------------------------------------------- -// IfConvertJoinStmts -// -// Move all the statements from a block onto the end of the start block. -// -// Arguments: -// fromBlock -- Source block -// -void OptIfConversionDsc::IfConvertJoinStmts(BasicBlock* fromBlock) -{ - Statement* stmtList1 = m_startBlock->firstStmt(); - Statement* stmtList2 = fromBlock->firstStmt(); - Statement* stmtLast1 = m_startBlock->lastStmt(); - Statement* stmtLast2 = fromBlock->lastStmt(); - stmtLast1->SetNextStmt(stmtList2); - stmtList2->SetPrevStmt(stmtLast1); - stmtList1->SetPrevStmt(stmtLast2); - fromBlock->SetFirstStmt(nullptr); -} - //----------------------------------------------------------------------------- // IfConvertDump // @@ -384,19 +363,24 @@ void OptIfConversionDsc::IfConvertJoinStmts(BasicBlock* fromBlock) #ifdef DEBUG void OptIfConversionDsc::IfConvertDump() { - assert(m_startBlock != nullptr); m_compiler->fgDumpBlock(m_startBlock); - BasicBlock* dumpBlock = m_startBlock->KindIs(BBJ_COND) ? m_startBlock->GetFalseTarget() : m_startBlock->GetTarget(); - for (; dumpBlock != m_finalBlock; dumpBlock = dumpBlock->GetUniqueSucc()) - { - m_compiler->fgDumpBlock(dumpBlock); - } - if (m_doElseConversion) + + bool beforeTransformation = m_startBlock->KindIs(BBJ_COND); + if (beforeTransformation) { - dumpBlock = m_startBlock->KindIs(BBJ_COND) ? m_startBlock->GetTrueTarget() : m_startBlock->GetTarget(); - for (; dumpBlock != m_finalBlock; dumpBlock = dumpBlock->GetUniqueSucc()) + // Dump all Then blocks + for (BasicBlock* bb = m_startBlock->GetFalseTarget(); bb != m_finalBlock; bb = bb->GetUniqueSucc()) + { + m_compiler->fgDumpBlock(bb); + } + + if (m_doElseConversion) { - m_compiler->fgDumpBlock(dumpBlock); + // Dump all Else blocks + for (BasicBlock* bb = m_startBlock->GetTrueTarget(); bb != m_finalBlock; bb = bb->GetUniqueSucc()) + { + m_compiler->fgDumpBlock(bb); + } } } } @@ -731,9 +715,8 @@ bool OptIfConversionDsc::optIfConvert(int* pReachabilityBudget) select = m_compiler->gtNewConditionalNode(GT_SELECT, m_cond, selectTrueInput, selectFalseInput, selectType); } + // Use the SELECT as the source of the Then STORE/RETURN. m_thenOperation.node->AddAllEffectsFlags(select); - - // Use the select as the source of the Then operation. if (m_mainOper == GT_STORE_LCL_VAR) { m_thenOperation.node->AsLclVar()->Data() = select; @@ -745,30 +728,47 @@ bool OptIfConversionDsc::optIfConvert(int* pReachabilityBudget) m_compiler->gtSetEvalOrder(m_thenOperation.node); m_compiler->fgSetStmtSeq(m_thenOperation.stmt); - // Remove statements. - last->gtBashToNOP(); - m_compiler->gtSetEvalOrder(last); - m_compiler->fgSetStmtSeq(m_startBlock->lastStmt()); - if (m_doElseConversion) + // Replace JTRUE with STORE(SELECT)/RETURN(SELECT) statement + m_compiler->fgInsertStmtBefore(m_startBlock, m_startBlock->lastStmt(), m_thenOperation.stmt); + m_compiler->fgRemoveStmt(m_startBlock, m_startBlock->lastStmt()); + m_thenOperation.block->SetFirstStmt(nullptr); + + BasicBlock* falseBb = m_startBlock->GetFalseTarget(); + BasicBlock* trueBb = m_startBlock->GetTrueTarget(); + + // JTRUE block now contains SELECT. Change it's kind and make it flow + // directly into block where flows merge, which is null in case of GT_RETURN. + if (m_mainOper == GT_RETURN) { - m_elseOperation.node->gtBashToNOP(); - m_compiler->gtSetEvalOrder(m_elseOperation.node); - m_compiler->fgSetStmtSeq(m_elseOperation.stmt); + m_startBlock->SetKindAndTargetEdge(BBJ_RETURN); } + else + { + FlowEdge* newEdge = + m_doElseConversion ? m_compiler->fgAddRefPred(m_finalBlock, m_startBlock) : m_startBlock->GetTrueEdge(); + m_startBlock->SetKindAndTargetEdge(BBJ_ALWAYS, newEdge); + } + assert(m_startBlock->GetUniqueSucc() == m_finalBlock); - // Merge all the blocks. - IfConvertJoinStmts(m_thenOperation.block); + // Remove all Then/Else blocks + auto removeBlocks = [&](BasicBlock* start) { + m_compiler->fgRemoveAllRefPreds(start, m_startBlock); + start->bbWeight = BB_ZERO_WEIGHT; + assert(start->bbPreds == nullptr); + + for (BasicBlock* bb = start; bb != m_finalBlock;) + { + BasicBlock* next = bb->GetUniqueSucc(); + m_compiler->fgRemoveBlock(bb, true); + bb = next; + } + }; + removeBlocks(falseBb); if (m_doElseConversion) { - IfConvertJoinStmts(m_elseOperation.block); + removeBlocks(trueBb); } - // Update the flow from the original block. - FlowEdge* const removedEdge = m_compiler->fgRemoveAllRefPreds(m_startBlock->GetFalseTarget(), m_startBlock); - FlowEdge* const retainedEdge = m_startBlock->GetTrueEdge(); - m_startBlock->SetKindAndTargetEdge(BBJ_ALWAYS, retainedEdge); - m_compiler->fgRepairProfileCondToUncond(m_startBlock, retainedEdge, removedEdge); - #ifdef DEBUG if (m_compiler->verbose) { diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 18670bb36147ee..7513b590f4cde4 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -10077,8 +10077,9 @@ void Compiler::impImportBlockCode(BasicBlock* block) } op1 = gtNewOperNode(GT_LCLHEAP, TYP_I_IMPL, op2); - // May throw a stack overflow exception. Obviously, we don't want locallocs to be CSE'd. - op1->gtFlags |= (GTF_EXCEPT | GTF_DONT_CSE); + // We do not model stack overflow from localloc as an exception side effect. + // Obviously, we don't want locallocs to be CSE'd. + op1->gtFlags |= GTF_DONT_CSE; // Request stack security for this method. setNeedsGSSecurityCookie(); diff --git a/src/coreclr/jit/lclmorph.cpp b/src/coreclr/jit/lclmorph.cpp index 8675ae841ed90f..61749ab4a8f947 100644 --- a/src/coreclr/jit/lclmorph.cpp +++ b/src/coreclr/jit/lclmorph.cpp @@ -1010,7 +1010,7 @@ class LocalAddressVisitor final : public GenTreeVisitor break; case GT_FIELD_ADDR: - if (MorphStructFieldAddress(node, 0) != BAD_VAR_NUM) + if (MorphStructFieldAddress(node, ValueSize(0)) != BAD_VAR_NUM) { goto LOCAL_NODE; } @@ -1595,32 +1595,10 @@ class LocalAddressVisitor final : public GenTreeVisitor unsigned lclNum = val.LclNum(); unsigned offset = val.Offset(); LclVarDsc* varDsc = m_compiler->lvaGetDesc(lclNum); - unsigned indirSize = node->AsIndir()->Size(); - bool isWide; + ValueSize lclSize = m_compiler->lvaLclValueSize(lclNum); + ValueSize indirSize = node->AsIndir()->ValueSize(); - // TODO-Cleanup: delete "indirSize == 0", use "Compiler::IsValidLclAddr". - if ((indirSize == 0) || ((offset + indirSize) > UINT16_MAX)) - { - // If we can't figure out the indirection size then treat it as a wide indirection. - // Additionally, treat indirections with large offsets as wide: local field nodes - // and the emitter do not support them. - isWide = true; - } - else - { - ClrSafeInt endOffset = ClrSafeInt(offset) + ClrSafeInt(indirSize); - - if (endOffset.IsOverflow()) - { - isWide = true; - } - else - { - isWide = endOffset.Value() > m_compiler->lvaLclExactSize(lclNum); - } - } - - if (isWide) + if (indirSize.IsNull() || m_compiler->IsWideAccess(lclNum, offset, indirSize)) { unsigned exposedLclNum = varDsc->lvIsStructField ? varDsc->lvParentLcl : lclNum; if (m_lclAddrAssertions != nullptr) @@ -2065,7 +2043,7 @@ class LocalAddressVisitor final : public GenTreeVisitor return false; } - unsigned fieldLclNum = MorphStructFieldAddress(addr, node->Size()); + unsigned fieldLclNum = MorphStructFieldAddress(addr, node->ValueSize()); if (fieldLclNum == BAD_VAR_NUM) { return false; @@ -2104,13 +2082,13 @@ class LocalAddressVisitor final : public GenTreeVisitor // // Arguments: // node - the address node - // accessSize - load/store size if known, zero otherwise + // accessSize - load/store value size // // Return Value: // Local number for the promoted field if the replacement was successful, // BAD_VAR_NUM otherwise. // - unsigned MorphStructFieldAddress(GenTree* node, unsigned accessSize) + unsigned MorphStructFieldAddress(GenTree* node, ValueSize accessSize) { unsigned offset = 0; bool isSpanLength = false; @@ -2138,16 +2116,16 @@ class LocalAddressVisitor final : public GenTreeVisitor } LclVarDsc* fieldVarDsc = m_compiler->lvaGetDesc(fieldLclNum); + ValueSize fieldSize = fieldVarDsc->lvValueSize(); // Span's Length is never negative unconditionally - if (isSpanLength && (accessSize == genTypeSize(TYP_INT))) + if (isSpanLength && (accessSize.GetExact() == genTypeSize(TYP_INT))) { - fieldVarDsc->SetIsNeverNegative(true); + unsigned exactSize = accessSize.GetExact(); + unsigned exactFieldSize = fieldSize.GetExact(); } - // Retargeting the indirection to reference the promoted field would make it "wide", exposing - // the whole parent struct (with all of its fields). - if (accessSize > genTypeSize(fieldVarDsc)) + if (!accessSize.IsNull() && m_compiler->IsWideAccess(fieldLclNum, 0, accessSize)) { return BAD_VAR_NUM; } diff --git a/src/coreclr/jit/lclvars.cpp b/src/coreclr/jit/lclvars.cpp index 49e339fcbf479a..acd4be1edf083e 100644 --- a/src/coreclr/jit/lclvars.cpp +++ b/src/coreclr/jit/lclvars.cpp @@ -4352,24 +4352,26 @@ void Compiler::lvaFixVirtualFrameOffsets() if ((lvaMonAcquired != BAD_VAR_NUM) && !opts.IsOSR()) { - int offset = lvaTable[lvaMonAcquired].GetStackOffset() + delta; + int offset = lvaTable[lvaMonAcquired].GetStackOffset() + (compCalleeRegsPushed << 3); lvaTable[lvaMonAcquired].SetStackOffset(offset); delta += lvaLclStackHomeSize(lvaMonAcquired); } +#ifndef TARGET_LOONGARCH64 if ((lvaAsyncExecutionContextVar != BAD_VAR_NUM) && !opts.IsOSR()) { - int offset = lvaTable[lvaAsyncExecutionContextVar].GetStackOffset() + delta; + int offset = lvaTable[lvaAsyncExecutionContextVar].GetStackOffset() + (compCalleeRegsPushed << 3); lvaTable[lvaAsyncExecutionContextVar].SetStackOffset(offset); delta += lvaLclStackHomeSize(lvaAsyncExecutionContextVar); } if ((lvaAsyncSynchronizationContextVar != BAD_VAR_NUM) && !opts.IsOSR()) { - int offset = lvaTable[lvaAsyncSynchronizationContextVar].GetStackOffset() + delta; + int offset = lvaTable[lvaAsyncSynchronizationContextVar].GetStackOffset() + (compCalleeRegsPushed << 3); lvaTable[lvaAsyncSynchronizationContextVar].SetStackOffset(offset); delta += lvaLclStackHomeSize(lvaAsyncSynchronizationContextVar); } +#endif JITDUMP("--- delta bump %d for FP frame\n", delta); } diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index 898539684c994a..7ad423c51ab822 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -5705,7 +5705,7 @@ GenTree* Lowering::LowerStoreLocCommon(GenTreeLclVarCommon* lclStore) { if (slotCount > 1) { -#if !defined(TARGET_RISCV64) && !defined(TARGET_LOONGARCH64) +#if !defined(TARGET_RISCV64) && !defined(TARGET_LOONGARCH64) && !defined(TARGET_WASM) assert(call->HasMultiRegRetVal()); #endif } @@ -11703,7 +11703,7 @@ void Lowering::TransformUnusedIndirection(GenTreeIndir* ind, Compiler* m_compile // LowerLclHeap: a common logic to lower LCLHEAP. // // Arguments: -// blkNode - the LCLHEAP node we are lowering. +// node - the LCLHEAP node we are lowering. // void Lowering::LowerLclHeap(GenTree* node) { diff --git a/src/coreclr/jit/lsraarm64.cpp b/src/coreclr/jit/lsraarm64.cpp index cf2164fc70b831..3236db623472cd 100644 --- a/src/coreclr/jit/lsraarm64.cpp +++ b/src/coreclr/jit/lsraarm64.cpp @@ -1389,6 +1389,11 @@ int LinearScan::BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree, int* pDstCou // Build any additional special cases switch (intrin.id) { + case NI_Sve2_GatherVectorInt16SignExtendNonTemporal: + case NI_Sve2_GatherVectorInt32SignExtendNonTemporal: + case NI_Sve2_GatherVectorNonTemporal: + case NI_Sve2_GatherVectorUInt16ZeroExtendNonTemporal: + case NI_Sve2_GatherVectorUInt32ZeroExtendNonTemporal: case NI_Sve2_Scatter16BitNarrowingNonTemporal: case NI_Sve2_Scatter32BitNarrowingNonTemporal: case NI_Sve2_ScatterNonTemporal: diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index 0add5dd01529e4..0531aef7d53e6c 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -948,11 +948,12 @@ void CallArgs::ArgsComplete(Compiler* comp, GenTreeCall* call) #if !FEATURE_FIXED_OUT_ARGS // On x86 we previously recorded a stack depth of zero when // morphing the register arguments of any GT_IND with a GTF_IND_RNGCHK flag - // Thus we can not reorder the argument after any stack based argument - // (Note that GT_LCLHEAP sets the GTF_EXCEPT flag so we don't need to - // check for it explicitly.) + // Thus we can not reorder the argument after any stack based argument. + // GT_LCLHEAP has the same stack depth constraint, but it no longer sets + // GTF_EXCEPT, so it must be checked explicitly here. // - if (argx->gtFlags & GTF_EXCEPT) + if (((argx->gtFlags & GTF_EXCEPT) != 0) || + (comp->compLocallocUsed && comp->gtTreeContainsOper(argx, GT_LCLHEAP))) { SetNeedsTemp(&arg); continue; @@ -960,15 +961,11 @@ void CallArgs::ArgsComplete(Compiler* comp, GenTreeCall* call) #else // For Arm/X64 we can't reorder a register argument that uses a GT_LCLHEAP // - if (argx->gtFlags & GTF_EXCEPT) + if (comp->compLocallocUsed && comp->gtTreeContainsOper(argx, GT_LCLHEAP)) { assert(comp->compLocallocUsed); - - if (comp->gtTreeContainsOper(argx, GT_LCLHEAP)) - { - SetNeedsTemp(&arg); - continue; - } + SetNeedsTemp(&arg); + continue; } #endif } @@ -8496,12 +8493,11 @@ GenTree* Compiler::fgMorphFinalizeIndir(GenTreeIndir* indir) if (!indir->IsVolatile() && !indir->TypeIs(TYP_STRUCT) && addr->OperIs(GT_LCL_ADDR)) { - unsigned size = indir->Size(); - unsigned offset = addr->AsLclVarCommon()->GetLclOffs(); - unsigned extent = offset + size; - unsigned lclSize = lvaLclExactSize(addr->AsLclVarCommon()->GetLclNum()); + int lclNum = addr->AsLclVarCommon()->GetLclNum(); + unsigned offset = addr->AsLclVarCommon()->GetLclOffs(); + ValueSize indirSize = indir->ValueSize(); - if ((extent <= lclSize) && (extent < UINT16_MAX)) + if (!IsWideAccess(lclNum, offset, indirSize)) { addr->ChangeType(indir->TypeGet()); if (indir->OperIs(GT_STOREIND)) @@ -8582,6 +8578,19 @@ GenTree* Compiler::fgOptimizeCast(GenTreeCast* cast) var_types castToType = cast->CastToType(); + // For small-int casts fed by a widening int->long, remove the widening so we truncate directly + // from the original int value. + if (varTypeIsSmall(castToType) && src->OperIs(GT_CAST) && !src->gtOverflow()) + { + GenTreeCast* widening = src->AsCast(); + if (varTypeIsLong(widening->CastToType()) && (genActualType(widening->CastFromType()) == TYP_INT)) + { + cast->CastOp() = widening->CastOp(); + DEBUG_DESTROY_NODE(widening); + src = cast->CastOp(); + } + } + // For indir-like nodes, we may be able to change their type to satisfy (and discard) the cast. if (varTypeIsSmall(castToType) && (genTypeSize(castToType) == genTypeSize(src)) && src->OperIs(GT_IND, GT_LCL_FLD)) @@ -10400,30 +10409,31 @@ GenTree* Compiler::fgOptimizeAddition(GenTreeOp* add) if (opts.OptimizationEnabled()) { - // Reduce local addresses: "ADD(LCL_ADDR, OFFSET)" => "LCL_FLD_ADDR". + // Reduce local addresses: "ADD(LCL_ADDR(BASE), OFFSET)" => "LCL_ADDR(BASE+OFFSET)". // if (op1->OperIs(GT_LCL_ADDR) && op2->IsCnsIntOrI()) { GenTreeLclVarCommon* lclAddrNode = op1->AsLclVarCommon(); GenTreeIntCon* offsetNode = op2->AsIntCon(); - if (FitsIn(offsetNode->IconValue())) + ssize_t consVal = offsetNode->IconValue(); + + // Note: the emitter does not expect out-of-bounds access for LCL_ADDR. + if (FitsIn(consVal) && IsValidLclAddr(lclAddrNode->GetLclNum(), (uint32_t)consVal)) { - unsigned offset = lclAddrNode->GetLclOffs() + static_cast(offsetNode->IconValue()); + ClrSafeInt newOffset = + ClrSafeInt(lclAddrNode->GetLclOffs()) + ClrSafeInt(consVal); + assert(!newOffset.IsOverflow()); - // Note: the emitter does not expect out-of-bounds access for LCL_FLD_ADDR. - if (FitsIn(offset) && (offset < lvaLclExactSize(lclAddrNode->GetLclNum()))) - { - lclAddrNode->SetOper(GT_LCL_ADDR); - lclAddrNode->AsLclFld()->SetLclOffs(offset); - assert(lvaGetDesc(lclAddrNode)->lvDoNotEnregister); + lclAddrNode->SetOper(GT_LCL_ADDR); + lclAddrNode->AsLclFld()->SetLclOffs(newOffset.Value()); + assert(lvaGetDesc(lclAddrNode)->lvDoNotEnregister); - lclAddrNode->SetVNsFromNode(add); + lclAddrNode->SetVNsFromNode(add); - DEBUG_DESTROY_NODE(offsetNode); - DEBUG_DESTROY_NODE(add); + DEBUG_DESTROY_NODE(offsetNode); + DEBUG_DESTROY_NODE(add); - return lclAddrNode; - } + return lclAddrNode; } } diff --git a/src/coreclr/jit/utils.h b/src/coreclr/jit/utils.h index b410c5ce6abb67..38c819e0672896 100644 --- a/src/coreclr/jit/utils.h +++ b/src/coreclr/jit/utils.h @@ -588,8 +588,7 @@ enum class ExceptionSetFlags : uint32_t ArithmeticException = 0x4, NullReferenceException = 0x8, IndexOutOfRangeException = 0x10, - StackOverflowException = 0x20, - UnknownException = 0x40, + UnknownException = 0x20, }; class HelperCallProperties diff --git a/src/coreclr/nativeaot/Runtime/loongarch64/GcProbe.S b/src/coreclr/nativeaot/Runtime/loongarch64/GcProbe.S index 118af7c53ca1ab..e022a907caa1c0 100644 --- a/src/coreclr/nativeaot/Runtime/loongarch64/GcProbe.S +++ b/src/coreclr/nativeaot/Runtime/loongarch64/GcProbe.S @@ -4,10 +4,11 @@ #include #include "AsmOffsets.inc" -#define PROBE_FRAME_SIZE 0x90 // 4 * 8 for fixed part of PInvokeTransitionFrame (fp, ra, m_pThread, m_Flags) + +#define PROBE_FRAME_SIZE 0xA0 // 4 * 8 for fixed part of PInvokeTransitionFrame (fp, ra, m_pThread, m_Flags) + // 9 * 8 for callee saved registers + // 1 * 8 for caller SP + - // 2 * 8 for int returns + + // 3 * 8 for int returns (a0, a1, a2) + + // 1 * 8 for alignment padding + // 2 * 8 for FP returns // See PUSH_COOP_PINVOKE_FRAME, this macro is very similar, but also saves return registers @@ -37,13 +38,15 @@ // Slot at $sp+0x68 is reserved for caller sp - // Save the integer return registers + // Save the integer return registers, a2 might contain an objectref (async continuation) st.d $a0, $sp, 0x70 st.d $a1, $sp, 0x78 + st.d $a2, $sp, 0x80 + // Slot at [sp, #0x88] is alignment padding // Save the FP return registers - fst.d $f0, $sp, 0x80 - fst.d $f1, $sp, 0x88 + fst.d $f0, $sp, 0x90 + fst.d $f1, $sp, 0x98 // Perform the rest of the PInvokeTransitionFrame initialization. st.d \threadReg, $sp, OFFSETOF__PInvokeTransitionFrame__m_pThread // Thread * (unused by stackwalker) @@ -66,10 +69,11 @@ // Restore the integer return registers ld.d $a0, $sp, 0x70 ld.d $a1, $sp, 0x78 + ld.d $a2, $sp, 0x80 // Restore the FP return registers - fld.d $f0, $sp, 0x80 - fld.d $f1, $sp, 0x88 + fld.d $f0, $sp, 0x90 + fld.d $f1, $sp, 0x98 // Restore callee saved registers EPILOG_RESTORE_REG_PAIR 23, 24, 0x20 @@ -89,25 +93,26 @@ // All registers correct for return to the original return address. // // Register state on exit: -// a2: thread pointer +// a4: thread pointer +// a0, a1, a2: preserved // .macro FixupHijackedCallstack - // a2 <- GetThread() - INLINE_GETTHREAD $a2 + // a4 <- GetThread() + INLINE_GETTHREAD $a4 // // Fix the stack by restoring the original return address // // Load m_pvHijackedReturnAddress - ld.d $ra, $a2, OFFSETOF__Thread__m_pvHijackedReturnAddress + ld.d $ra, $a4, OFFSETOF__Thread__m_pvHijackedReturnAddress // // Clear hijack state // // Clear m_ppvHijackedReturnAddressLocation and m_pvHijackedReturnAddress - st.d $zero, $a2, OFFSETOF__Thread__m_ppvHijackedReturnAddressLocation - st.d $zero, $a2, OFFSETOF__Thread__m_ppvHijackedReturnAddressLocation + 8 + st.d $zero, $a4, OFFSETOF__Thread__m_ppvHijackedReturnAddressLocation + st.d $zero, $a4, OFFSETOF__Thread__m_ppvHijackedReturnAddressLocation + 8 .endm // @@ -122,16 +127,16 @@ NESTED_ENTRY RhpGcProbeHijack, _TEXT, NoHandler jirl $r0, $ra, 0 LOCAL_LABEL(WaitForGC): - li.d $t3, (DEFAULT_FRAME_SAVE_FLAGS + PTFF_SAVE_R4 + PTFF_SAVE_R5 + PTFF_THREAD_HIJACK) + li.d $t3, (DEFAULT_FRAME_SAVE_FLAGS + PTFF_SAVE_R4 + PTFF_SAVE_R5 + PTFF_SAVE_R6 + PTFF_THREAD_HIJACK) b C_FUNC(RhpWaitForGC) NESTED_END RhpGcProbeHijack .global C_FUNC(RhpThrowHwEx) NESTED_ENTRY RhpWaitForGC, _TEXT, NoHandler - PUSH_PROBE_FRAME $a2, $a3, $t3 + PUSH_PROBE_FRAME $a4, $a3, $t3 - ld.d $a0, $a2, OFFSETOF__Thread__m_pDeferredTransitionFrame + ld.d $a0, $a4, OFFSETOF__Thread__m_pDeferredTransitionFrame bl C_FUNC(RhpWaitForGC2) POP_PROBE_FRAME diff --git a/src/coreclr/nativeaot/Runtime/unix/unixasmmacrosloongarch64.inc b/src/coreclr/nativeaot/Runtime/unix/unixasmmacrosloongarch64.inc index 265a188f82eb4a..cf3583aae5ba87 100644 --- a/src/coreclr/nativeaot/Runtime/unix/unixasmmacrosloongarch64.inc +++ b/src/coreclr/nativeaot/Runtime/unix/unixasmmacrosloongarch64.inc @@ -198,6 +198,7 @@ C_FUNC(\Name): #define PTFF_SAVE_SP 0x00000200 #define PTFF_SAVE_R4 0x00000800 #define PTFF_SAVE_R5 0x00001000 +#define PTFF_SAVE_R6 0x00002000 #define PTFF_SAVE_ALL_PRESERVED 0x000001FF // NOTE: r23-r31 #define PTFF_THREAD_HIJACK 0x80000000 diff --git a/src/coreclr/scripts/superpmi.py b/src/coreclr/scripts/superpmi.py index 057a130765a2b3..6c9740406ef036 100644 --- a/src/coreclr/scripts/superpmi.py +++ b/src/coreclr/scripts/superpmi.py @@ -20,6 +20,7 @@ import asyncio import csv import datetime +import html import json import locale import logging @@ -2997,7 +2998,7 @@ def write_example_diffs_to_markdown_summary(write_fh, asm_diffs): for (func_name, diff, diff_text) in examples_to_put_in_summary: base_size = int(diff["Base ActualCodeBytes"]) diff_size = int(diff["Diff ActualCodeBytes"]) - with DetailsSection(write_fh, "{} ({}) : {}".format(format_delta(base_size, diff_size), compute_and_format_pct(base_size, diff_size), func_name)): + with DetailsSection(write_fh, "{} ({}) : {}".format(format_delta(base_size, diff_size), compute_and_format_pct(base_size, diff_size), html.escape(func_name))): write_fh.write(diff_text) ################################################################################ diff --git a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/AssemblyStubNode.cs b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/AssemblyStubNode.cs index e31f93bb39bb47..9fdb87be78def2 100644 --- a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/AssemblyStubNode.cs +++ b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/AssemblyStubNode.cs @@ -7,6 +7,9 @@ namespace ILCompiler.DependencyAnalysis { + // TODO-Wasm: Some instances of AssemblyStubNode will need to implement INodeWithTypeSignature + // if they need to be callable from Wasm, though it may not make sense for the base + // class to implement INodeWithTypeSignature. public abstract class AssemblyStubNode : ObjectNode, ISymbolDefinitionNode { public AssemblyStubNode() diff --git a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/INodeWithTypeSignature.cs b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/INodeWithTypeSignature.cs new file mode 100644 index 00000000000000..0471d3ca296a63 --- /dev/null +++ b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/INodeWithTypeSignature.cs @@ -0,0 +1,18 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +using Internal.TypeSystem; + +namespace ILCompiler.DependencyAnalysis +{ + public interface INodeWithTypeSignature : ISymbolDefinitionNode + { + MethodSignature Signature { get; } + bool IsUnmanagedCallersOnly { get; } + } + + public interface IMethodCodeNodeWithTypeSignature : IMethodNode, INodeWithTypeSignature + { + MethodSignature INodeWithTypeSignature.Signature => Method.Signature; + bool INodeWithTypeSignature.IsUnmanagedCallersOnly => Method.IsUnmanagedCallersOnly; + } +} diff --git a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/ObjectNode.cs b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/ObjectNode.cs index 327447571686fa..151fa1e8f587bf 100644 --- a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/ObjectNode.cs +++ b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/ObjectNode.cs @@ -68,6 +68,14 @@ public sealed override IEnumerable GetStaticDependencies(No } } + if (factory.Target.IsWasm && this is IMethodCodeNodeWithTypeSignature wasmMethodCodeNode) + { + dependencies ??= new DependencyList(); + + WasmTypeNode wasmTypeNode = factory.WasmTypeNode(wasmMethodCodeNode.Method); + dependencies.Add(wasmTypeNode, "Wasm Method Code Nodes Require Signature"); + } + if (dependencies == null) return Array.Empty(); else diff --git a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs index fa68031839b1d4..d8f541b8f88d03 100644 --- a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs +++ b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs @@ -449,6 +449,7 @@ private static unsafe void PutLoongArch64PC12(uint* pCode, long imm) Debug.Assert((pcInstr & 0xFE000000) == 0x1a000000); // Must be pcalau12i + pcInstr &= 0xFE00001F; // keep bits 31-25, 4-0 // Assemble the pc-relative high 20 bits of 'imm' into the pcalau12i instruction pcInstr |= (uint)((imm >> 7) & 0x1FFFFE0); @@ -456,7 +457,8 @@ private static unsafe void PutLoongArch64PC12(uint* pCode, long imm) pcInstr = *(pCode + 1); - // Assemble the pc-relative low 12 bits of 'imm' into the addid or ld instruction + pcInstr &= 0xFFC003FF; // keep bits 31-22, 9-0 + // Assemble the pc-relative low 12 bits of 'imm' into the addi.d or ld instruction pcInstr |= (uint)((imm & 0xFFF) << 10); *(pCode + 1) = pcInstr; // write the assembled instruction @@ -493,6 +495,7 @@ private static unsafe void PutLoongArch64JIR(uint* pCode, long imm38) long imm = imm38 + relOff; relOff = (((imm & 0x1ffff) - relOff) >> 2) & 0xffff; + pcInstr &= 0xFE00001F; // keep bits 31-25, 4-0 // Assemble the pc-relative high 20 bits of 'imm38' into the pcaddu18i instruction pcInstr |= (uint)(((imm >> 18) & 0xFFFFF) << 5); @@ -500,6 +503,7 @@ private static unsafe void PutLoongArch64JIR(uint* pCode, long imm38) pcInstr = *(pCode + 1); + pcInstr &= 0xFC0003FF; // keep bits 31-26, 9-0 // Assemble the pc-relative low 18 bits of 'imm38' into the jirl instruction pcInstr |= (uint)(relOff << 10); diff --git a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Target_Wasm/WasmTypes.cs b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Target_Wasm/WasmTypes.cs index da37129e4b501e..f226eed7b825fe 100644 --- a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Target_Wasm/WasmTypes.cs +++ b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Target_Wasm/WasmTypes.cs @@ -4,6 +4,7 @@ using System; using System.Diagnostics; using System.Linq; + using ILCompiler.ObjectWriter; using Internal.JitInterface; diff --git a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Target_Wasm/WasmTypeNode.cs b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/WasmTypeNode.cs similarity index 96% rename from src/coreclr/tools/Common/Compiler/DependencyAnalysis/Target_Wasm/WasmTypeNode.cs rename to src/coreclr/tools/Common/Compiler/DependencyAnalysis/WasmTypeNode.cs index 4ef0659e166c1a..20deff75fe2e83 100644 --- a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Target_Wasm/WasmTypeNode.cs +++ b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/WasmTypeNode.cs @@ -2,10 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using ILCompiler.DependencyAnalysis; + using ILCompiler.ObjectWriter; +using ILCompiler.DependencyAnalysis.Wasm; -namespace ILCompiler.DependencyAnalysis.Wasm +namespace ILCompiler.DependencyAnalysis { // // Represents a WASM type signature, e.g. "(i32, i32) -> (i64)". Used as a relocation target for things like 'call_indirect'. diff --git a/src/coreclr/tools/Common/Compiler/ObjectWriter/ObjectWriter.cs b/src/coreclr/tools/Common/Compiler/ObjectWriter/ObjectWriter.cs index 9f0f397a364a07..a4eca181141b60 100644 --- a/src/coreclr/tools/Common/Compiler/ObjectWriter/ObjectWriter.cs +++ b/src/coreclr/tools/Common/Compiler/ObjectWriter/ObjectWriter.cs @@ -12,11 +12,12 @@ using ILCompiler.DependencyAnalysisFramework; using Internal.Text; using Internal.TypeSystem; + using static ILCompiler.DependencyAnalysis.ObjectNode; using static ILCompiler.DependencyAnalysis.RelocType; using ObjectData = ILCompiler.DependencyAnalysis.ObjectNode.ObjectData; + using CodeDataLayout = CodeDataLayoutMode.CodeDataLayout; -using ILCompiler.DependencyAnalysis.Wasm; namespace ILCompiler.ObjectWriter { @@ -441,17 +442,27 @@ public virtual void EmitObject(Stream outputFileStream, IReadOnlyCollection _uniqueSignatures = new(); private Dictionary _uniqueSymbols = new(); - private int _signatureCount = 0; private int _methodCount = 0; private protected override void RecordMethodSignature(WasmTypeNode signature) { - int signatureIndex = _signatureCount; var mangledNameBuilder = new Utf8StringBuilder(); signature.AppendMangledName(_nodeFactory.NameMangler, mangledNameBuilder); Utf8String mangledName = mangledNameBuilder.ToUtf8String(); - // Note that we do not expect duplicates here, since crossgen's node cache should handle this and all nodes representing - // identical signatures in a module should point to the same node instance - _uniqueSignatures.Add(mangledName, signatureIndex); - _signatureCount++; + // Note that we do not expect duplicates here, crossgen should deduplicate signatures already + // using the node cache, so we can simply add the new signature with the next available index. + _uniqueSignatures.Add(mangledName, _uniqueSignatures.Count); } - private protected override void RecordMethodDeclaration(ISymbolDefinitionNode symbol, MethodDesc desc) + private protected override void RecordMethodDeclaration(INodeWithTypeSignature node, MethodDesc desc) { WriteSignatureIndexForFunction(desc); - _uniqueSymbols.Add(symbol.GetMangledName(_nodeFactory.NameMangler), _methodCount); + _uniqueSymbols.Add(node.GetMangledName(_nodeFactory.NameMangler), _methodCount); _methodCount++; } diff --git a/src/coreclr/tools/Common/JitInterface/WasmLowering.cs b/src/coreclr/tools/Common/JitInterface/WasmLowering.cs index 0db56ce99bd138..570f2d03c731f3 100644 --- a/src/coreclr/tools/Common/JitInterface/WasmLowering.cs +++ b/src/coreclr/tools/Common/JitInterface/WasmLowering.cs @@ -4,7 +4,9 @@ using System; using System.Collections.Generic; using System.Diagnostics; + using ILCompiler.DependencyAnalysis.Wasm; + using Internal.TypeSystem; namespace Internal.JitInterface diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NodeFactory.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NodeFactory.cs index 820cf40f5813be..44f752a62fc035 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NodeFactory.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NodeFactory.cs @@ -7,6 +7,7 @@ using System.Diagnostics; using System.Text; +using ILCompiler.DependencyAnalysis.Wasm; using ILCompiler.DependencyAnalysisFramework; using Internal.IL; @@ -613,6 +614,11 @@ private void CreateNodeCaches() return new AnalysisCharacteristicNode(c); }); + _wasmTypeNodes = new NodeCache(key => + { + return new WasmTypeNode(key); + }); + NativeLayout = new NativeLayoutHelper(this); } @@ -1569,6 +1575,17 @@ public AnalysisCharacteristicNode AnalysisCharacteristic(string ch) return _analysisCharacteristics.GetOrAdd(ch); } + private NodeCache _wasmTypeNodes; + + // TODO-Wasm: Do not use WasmFuncType directly as the key for better + // memory efficiency on lookup + public WasmTypeNode WasmTypeNode(MethodDesc desc) + { + // TODO-Wasm: Construct proper function type based on the passed in MethodDesc + // once we have defined lowering rules for signatures in NativeAOT. + throw new NotImplementedException("NAOT wasm type signature lowering not yet implemented"); + } + /// /// Returns alternative symbol name that object writer should produce for given symbols /// in addition to the regular one. diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj b/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj index fecf02a45a3c46..c4061f8c4af147 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj @@ -309,6 +309,8 @@ + + @@ -325,7 +327,6 @@ - diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DelayLoadHelperMethodImport.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DelayLoadHelperMethodImport.cs index 4c73a0ab08bcab..980dfc535ceb88 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DelayLoadHelperMethodImport.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DelayLoadHelperMethodImport.cs @@ -15,7 +15,7 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun /// In addition to PrecodeHelperImport instances of this import type emit GC ref map /// entries into the R2R executable. /// - public class DelayLoadHelperMethodImport : DelayLoadHelperImport, IMethodNode + public class DelayLoadHelperMethodImport : DelayLoadHelperImport, IMethodCodeNodeWithTypeSignature { private readonly MethodWithToken _method; diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DelayLoadMethodImport.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DelayLoadMethodImport.cs index dd0d49c8db19c2..3bdef8fb2f8be4 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DelayLoadMethodImport.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DelayLoadMethodImport.cs @@ -9,7 +9,7 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun { - public class DelayLoadMethodImport : DelayLoadHelperImport, IMethodNode + public class DelayLoadMethodImport : DelayLoadHelperImport, IMethodCodeNodeWithTypeSignature { private readonly MethodWithGCInfo _localMethod; diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/MethodWithGCInfo.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/MethodWithGCInfo.cs index aa3b9efa2f1526..0f65826a2c2d0e 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/MethodWithGCInfo.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/MethodWithGCInfo.cs @@ -13,7 +13,7 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun { - public class MethodWithGCInfo : ObjectNode, IMethodBodyNode, ISymbolDefinitionNode + public class MethodWithGCInfo : ObjectNode, IMethodBodyNode, IMethodCodeNodeWithTypeSignature { public readonly MethodGCInfoNode GCInfoNode; diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/Target_Wasm/ImportThunk.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/Target_Wasm/ImportThunk.cs index e84b9e8a4f381e..1f606488623bfa 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/Target_Wasm/ImportThunk.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/Target_Wasm/ImportThunk.cs @@ -3,6 +3,7 @@ using System; using System.Diagnostics; + using ILCompiler.DependencyAnalysis.Wasm; namespace ILCompiler.DependencyAnalysis.ReadyToRun diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs index b8fe7c2466f5f6..8a9602d24f51ef 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs @@ -1096,5 +1096,13 @@ public WasmTypeNode WasmTypeNode(CorInfoWasmType[] types) WasmFuncType funcType = WasmFuncType.FromCorInfoSignature(types); return _wasmTypeNodes.GetOrAdd(funcType); } + + // TODO-Wasm: Do not use WasmFuncType directly as the key for better + // memory efficiency on lookup + public WasmTypeNode WasmTypeNode(MethodDesc method) + { + WasmFuncType funcType = WasmLowering.GetSignature(method); + return _wasmTypeNodes.GetOrAdd(funcType); + } } } diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj index 1d78e70b1f47a4..e57807fa2c0c1c 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj @@ -83,6 +83,7 @@ + @@ -96,6 +97,7 @@ + @@ -113,7 +115,6 @@ - diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs index 3b9259043aec10..c5e2d1f8ca40c3 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs @@ -24,6 +24,7 @@ using ILCompiler.DependencyAnalysis; using ILCompiler.DependencyAnalysis.ReadyToRun; using ILCompiler.DependencyAnalysis.Wasm; + using System.Text; using System.Runtime.CompilerServices; using ILCompiler.ReadyToRun.TypeSystem; diff --git a/src/coreclr/tools/aot/ILCompiler.RyuJit/Compiler/DependencyAnalysis/MethodCodeNode.cs b/src/coreclr/tools/aot/ILCompiler.RyuJit/Compiler/DependencyAnalysis/MethodCodeNode.cs index 7681e8c062dc27..64920d89a0b951 100644 --- a/src/coreclr/tools/aot/ILCompiler.RyuJit/Compiler/DependencyAnalysis/MethodCodeNode.cs +++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/Compiler/DependencyAnalysis/MethodCodeNode.cs @@ -15,7 +15,7 @@ namespace ILCompiler.DependencyAnalysis { [DebuggerTypeProxy(typeof(MethodCodeNodeDebugView))] - public class MethodCodeNode : ObjectNode, IMethodBodyNode, INodeWithCodeInfo, INodeWithDebugInfo, ISymbolDefinitionNode, ISpecialUnboxThunkNode + public class MethodCodeNode : ObjectNode, IMethodBodyNode, INodeWithCodeInfo, INodeWithDebugInfo, ISpecialUnboxThunkNode, IMethodCodeNodeWithTypeSignature { private MethodDesc _method; private ObjectData _methodCode; diff --git a/src/coreclr/utilcode/util.cpp b/src/coreclr/utilcode/util.cpp index 4efc5bd767c77c..b85a788096c56b 100644 --- a/src/coreclr/utilcode/util.cpp +++ b/src/coreclr/utilcode/util.cpp @@ -2185,6 +2185,7 @@ void PutLoongArch64PC12(UINT32 * pCode, INT64 imm) _ASSERTE((pcInstr & 0xFE000000) == 0x1a000000); // Must be pcalau12i + pcInstr &= 0xFE00001F; // keep bits 31-25, 4-0 // Assemble the pc-relative high 20 bits of 'imm' into the pcalau12i instruction pcInstr |= (UINT32)((imm >> 7) & 0x1FFFFE0); @@ -2192,6 +2193,7 @@ void PutLoongArch64PC12(UINT32 * pCode, INT64 imm) pcInstr = *(pCode + 1); + pcInstr &= 0xFFC003FF; // keep bits 31-22, 9-0 // Assemble the pc-relative low 12 bits of 'imm' into the addid or ld instruction pcInstr |= (UINT32)((imm & 0xFFF) << 10); @@ -2218,6 +2220,7 @@ void PutLoongArch64JIR(UINT32 * pCode, INT64 imm38) INT64 imm = imm38 + relOff; relOff = (((imm & 0x1ffff) - relOff) >> 2) & 0xffff; + pcInstr &= 0xFE00001F; // keep bits 31-25, 4-0 // Assemble the pc-relative high 20 bits of 'imm38' into the pcaddu18i instruction pcInstr |= (UINT32)(((imm >> 18) & 0xFFFFF) << 5); @@ -2225,6 +2228,7 @@ void PutLoongArch64JIR(UINT32 * pCode, INT64 imm38) pcInstr = *(pCode + 1); + pcInstr &= 0xFC0003FF; // keep bits 31-26, 9-0 // Assemble the pc-relative low 18 bits of 'imm38' into the jirl instruction pcInstr |= (UINT32)(relOff << 10); diff --git a/src/coreclr/vm/appdomain.cpp b/src/coreclr/vm/appdomain.cpp index 88d6b1642b0f24..4b519cb48aa8e9 100644 --- a/src/coreclr/vm/appdomain.cpp +++ b/src/coreclr/vm/appdomain.cpp @@ -2537,15 +2537,15 @@ Assembly *AppDomain::LoadAssembly(FileLoadLock *pLock, FileLoadLevel targetLevel } CONTRACT_END; - Assembly *pAssembly = pLock->GetAssembly(); - // Make sure we release the lock on exit FileLoadLockRefHolder lockRef(pLock); // Do a quick out check for the already loaded case. if (pLock->GetLoadLevel() >= targetLevel) { + Assembly* pAssembly = pLock->GetAssembly(); _ASSERTE(pAssembly != nullptr); + pAssembly->ThrowIfError(targetLevel); RETURN pAssembly; @@ -2616,7 +2616,7 @@ Assembly *AppDomain::LoadAssembly(FileLoadLock *pLock, FileLoadLevel targetLevel fileLoadLevelName[pLock->GetLoadLevel()])); } - pAssembly = pLock->GetAssembly(); + Assembly* pAssembly = pLock->GetAssembly(); _ASSERTE(pAssembly != nullptr); // We should always be loading to at least FILE_LOAD_ALLOCATE, so the assembly should be created // There may have been an error stored on the domain file by another thread, or from a previous load diff --git a/src/coreclr/vm/comcache.h b/src/coreclr/vm/comcache.h index 61059b9c9cec4b..2f02827f3879a2 100644 --- a/src/coreclr/vm/comcache.h +++ b/src/coreclr/vm/comcache.h @@ -262,6 +262,15 @@ struct InterfaceEntry // will not try and optimize reads and writes to them. Volatile m_pMT; // Interface asked for Volatile m_pUnknown; // Result of query + + friend struct ::cdac_data; +}; + +template<> +struct cdac_data +{ + static constexpr size_t MethodTable = offsetof(InterfaceEntry, m_pMT); + static constexpr size_t Unknown = offsetof(InterfaceEntry, m_pUnknown); }; class CtxEntryCacheTraits : public DefaultSHashTraits diff --git a/src/coreclr/vm/datadescriptor/datadescriptor.inc b/src/coreclr/vm/datadescriptor/datadescriptor.inc index 48a72a4040c40f..61b49340a39c2d 100644 --- a/src/coreclr/vm/datadescriptor/datadescriptor.inc +++ b/src/coreclr/vm/datadescriptor/datadescriptor.inc @@ -1115,12 +1115,19 @@ CDAC_TYPE_FIELD(RCW, /*pointer*/, NextRCW, cdac_data::NextRCW) CDAC_TYPE_FIELD(RCW, /*uint32*/, Flags, cdac_data::Flags) CDAC_TYPE_FIELD(RCW, /*pointer*/, CtxCookie, cdac_data::CtxCookie) CDAC_TYPE_FIELD(RCW, /*pointer*/, CtxEntry, cdac_data::CtxEntry) +CDAC_TYPE_FIELD(RCW, /*inline array*/, InterfaceEntries, cdac_data::InterfaceEntries) CDAC_TYPE_END(RCW) CDAC_TYPE_BEGIN(CtxEntry) CDAC_TYPE_INDETERMINATE(CtxEntry) CDAC_TYPE_FIELD(CtxEntry, /*pointer*/, STAThread, cdac_data::STAThread) CDAC_TYPE_END(CtxEntry) + +CDAC_TYPE_BEGIN(InterfaceEntry) +CDAC_TYPE_SIZE(sizeof(InterfaceEntry)) +CDAC_TYPE_FIELD(InterfaceEntry, /*pointer*/, MethodTable, cdac_data::MethodTable) +CDAC_TYPE_FIELD(InterfaceEntry, /*pointer*/, Unknown, cdac_data::Unknown) +CDAC_TYPE_END(InterfaceEntry) #endif // FEATURE_COMINTEROP #ifdef FEATURE_COMWRAPPERS @@ -1306,6 +1313,7 @@ CDAC_GLOBAL_POINTER(TearOffAddRef, &g_cdacTearOffAddRef) CDAC_GLOBAL_POINTER(TearOffAddRefSimple, &g_cdacTearOffAddRefSimple) CDAC_GLOBAL_POINTER(TearOffAddRefSimpleInner, &g_cdacTearOffAddRefSimpleInner) CDAC_GLOBAL_POINTER(RCWCleanupList, &g_pRCWCleanupList) +CDAC_GLOBAL(RCWInterfaceCacheSize, uint32, INTERFACE_ENTRY_CACHE_SIZE) #endif // FEATURE_COMINTEROP // It is important for the subdescriptor pointers to be the last pointers in the global structure. diff --git a/src/coreclr/vm/loongarch64/asmhelpers.S b/src/coreclr/vm/loongarch64/asmhelpers.S index 9f424c39dd30f5..bd6b7beec16007 100644 --- a/src/coreclr/vm/loongarch64/asmhelpers.S +++ b/src/coreclr/vm/loongarch64/asmhelpers.S @@ -637,10 +637,12 @@ NESTED_ENTRY OnHijackTripThread, _TEXT, NoHandler // save any integral return value(s) st.d $a0, $sp, 88 st.d $a1, $sp, 96 + // save async continuation return value + st.d $a2, $sp, 104 // save any FP return value(s) - fst.d $f0, $sp, 104 - fst.d $f1, $sp, 112 + fst.d $f0, $sp, 112 + fst.d $f1, $sp, 120 ori $a0, $sp, 0 bl C_FUNC(OnHijackWorker) @@ -650,10 +652,12 @@ NESTED_ENTRY OnHijackTripThread, _TEXT, NoHandler // restore any integral return value(s) ld.d $a0, $sp, 88 ld.d $a1, $sp, 96 + // restore async continuation return value + ld.d $a2, $sp, 104 // restore any FP return value(s) - fld.d $f0, $sp, 104 - fld.d $f1, $sp, 112 + fld.d $f0, $sp, 112 + fld.d $f1, $sp, 120 EPILOG_RESTORE_REG_PAIR 23, 24, 16 EPILOG_RESTORE_REG_PAIR 25, 26, 32 diff --git a/src/coreclr/vm/loongarch64/cgencpu.h b/src/coreclr/vm/loongarch64/cgencpu.h index eb12a56d8dfd19..039a85d1782c02 100644 --- a/src/coreclr/vm/loongarch64/cgencpu.h +++ b/src/coreclr/vm/loongarch64/cgencpu.h @@ -429,6 +429,11 @@ struct HijackArgs size_t ReturnValue[2]; }; union + { + DWORD64 A2; + size_t AsyncRet; + }; + union { struct { DWORD64 F0; diff --git a/src/coreclr/vm/loongarch64/stubs.cpp b/src/coreclr/vm/loongarch64/stubs.cpp index b974c9511f3a63..8f69312046cb30 100644 --- a/src/coreclr/vm/loongarch64/stubs.cpp +++ b/src/coreclr/vm/loongarch64/stubs.cpp @@ -474,9 +474,11 @@ void HijackFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFloats pRD->pCurrentContext->A0 = m_Args->A0; pRD->pCurrentContext->A1 = m_Args->A1; + pRD->pCurrentContext->A2 = m_Args->A2; pRD->volatileCurrContextPointers.A0 = &m_Args->A0; pRD->volatileCurrContextPointers.A1 = &m_Args->A1; + pRD->volatileCurrContextPointers.A2 = &m_Args->A2; pRD->pCurrentContext->S0 = m_Args->S0; pRD->pCurrentContext->S1 = m_Args->S1; diff --git a/src/coreclr/vm/prestub.cpp b/src/coreclr/vm/prestub.cpp index b46b1bfefc7b97..fafa016af69e3c 100644 --- a/src/coreclr/vm/prestub.cpp +++ b/src/coreclr/vm/prestub.cpp @@ -2405,6 +2405,11 @@ PCODE MethodDesc::DoPrestub(MethodTable *pDispatchingMT, CallerGCMode callerGCMo void* ilStubInterpData = PortableEntryPoint::GetInterpreterData(pCode); _ASSERTE(ilStubInterpData != NULL); SetInterpreterCode((InterpByteCodeStart*)ilStubInterpData); + + // Use this method's own PortableEntryPoint rather than the stub's. + // It is required to maintain 1:1 mapping between MethodDesc and its entrypoint. + pCode = GetPortableEntryPoint(); + PortableEntryPoint::SetInterpreterData(pCode, (PCODE)(TADDR)ilStubInterpData); SetCodeEntryPoint(pCode); #else // !FEATURE_PORTABLE_ENTRYPOINTS if (!GetOrCreatePrecode()->SetTargetInterlocked(pStub->GetEntryPoint())) diff --git a/src/coreclr/vm/runtimecallablewrapper.h b/src/coreclr/vm/runtimecallablewrapper.h index 54ad924248ffe8..fee5c74177ee78 100644 --- a/src/coreclr/vm/runtimecallablewrapper.h +++ b/src/coreclr/vm/runtimecallablewrapper.h @@ -542,7 +542,6 @@ private : // IUnkEntry needs to access m_UnkEntry field friend IUnkEntry; - // cdac_data needs access to m_UnkEntry friend struct ::cdac_data; private : @@ -591,6 +590,7 @@ struct cdac_data static constexpr size_t Flags = offsetof(RCW, m_Flags); static constexpr size_t CtxCookie = offsetof(RCW, m_UnkEntry) + offsetof(IUnkEntry, m_pCtxCookie); static constexpr size_t CtxEntry = offsetof(RCW, m_UnkEntry) + offsetof(IUnkEntry, m_pCtxEntry); + static constexpr size_t InterfaceEntries = offsetof(RCW, m_aInterfaceEntries); }; inline RCW::CreationFlags operator|(RCW::CreationFlags lhs, RCW::CreationFlags rhs) diff --git a/src/libraries/Common/src/SourceGenerators/DiagnosticInfo.cs b/src/libraries/Common/src/SourceGenerators/DiagnosticInfo.cs deleted file mode 100644 index 74f44f99c62baa..00000000000000 --- a/src/libraries/Common/src/SourceGenerators/DiagnosticInfo.cs +++ /dev/null @@ -1,60 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Linq; -using System.Numerics.Hashing; -using Microsoft.CodeAnalysis; - -namespace SourceGenerators; - -/// -/// Descriptor for diagnostic instances using structural equality comparison. -/// Provides a work-around for https://github.com/dotnet/roslyn/issues/68291. -/// -internal readonly struct DiagnosticInfo : IEquatable -{ - public DiagnosticDescriptor Descriptor { get; private init; } - public object?[] MessageArgs { get; private init; } - public Location? Location { get; private init; } - - public static DiagnosticInfo Create(DiagnosticDescriptor descriptor, Location? location, object?[]? messageArgs) - { - Location? trimmedLocation = location is null ? null : GetTrimmedLocation(location); - - return new DiagnosticInfo - { - Descriptor = descriptor, - Location = trimmedLocation, - MessageArgs = messageArgs ?? Array.Empty() - }; - - // Creates a copy of the Location instance that does not capture a reference to Compilation. - static Location GetTrimmedLocation(Location location) - => Location.Create(location.SourceTree?.FilePath ?? "", location.SourceSpan, location.GetLineSpan().Span); - } - - public Diagnostic CreateDiagnostic() - => Diagnostic.Create(Descriptor, Location, MessageArgs); - - public override readonly bool Equals(object? obj) => obj is DiagnosticInfo info && Equals(info); - - public readonly bool Equals(DiagnosticInfo other) - { - return Descriptor.Equals(other.Descriptor) && - MessageArgs.SequenceEqual(other.MessageArgs) && - Location == other.Location; - } - - public override readonly int GetHashCode() - { - int hashCode = Descriptor.GetHashCode(); - foreach (object? messageArg in MessageArgs) - { - hashCode = HashHelpers.Combine(hashCode, messageArg?.GetHashCode() ?? 0); - } - - hashCode = HashHelpers.Combine(hashCode, Location?.GetHashCode() ?? 0); - return hashCode; - } -} diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1Reader/AsnValueReader.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1Reader/AsnValueReader.cs deleted file mode 100644 index ea9c1c3c7cadae..00000000000000 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1Reader/AsnValueReader.cs +++ /dev/null @@ -1,258 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Numerics; -using System.Security.Cryptography; - -namespace System.Formats.Asn1 -{ - internal ref struct AsnValueReader - { - private static readonly byte[] s_singleByte = new byte[1]; - - private ReadOnlySpan _span; - private readonly AsnEncodingRules _ruleSet; - - internal AsnValueReader(ReadOnlySpan span, AsnEncodingRules ruleSet) - { - _span = span; - _ruleSet = ruleSet; - } - - internal bool HasData => !_span.IsEmpty; - - internal void ThrowIfNotEmpty() - { - if (!_span.IsEmpty) - { - new AsnReader(s_singleByte, _ruleSet).ThrowIfNotEmpty(); - } - } - - internal Asn1Tag PeekTag() - { - return Asn1Tag.Decode(_span, out _); - } - - internal ReadOnlySpan PeekContentBytes() - { - AsnDecoder.ReadEncodedValue( - _span, - _ruleSet, - out int contentOffset, - out int contentLength, - out _); - - return _span.Slice(contentOffset, contentLength); - } - - internal ReadOnlySpan PeekEncodedValue() - { - AsnDecoder.ReadEncodedValue(_span, _ruleSet, out _, out _, out int consumed); - return _span.Slice(0, consumed); - } - - internal ReadOnlySpan ReadEncodedValue() - { - ReadOnlySpan value = PeekEncodedValue(); - _span = _span.Slice(value.Length); - return value; - } - - internal bool ReadBoolean(Asn1Tag? expectedTag = default) - { - bool ret = AsnDecoder.ReadBoolean(_span, _ruleSet, out int consumed, expectedTag); - _span = _span.Slice(consumed); - return ret; - } - - internal BigInteger ReadInteger(Asn1Tag? expectedTag = default) - { - BigInteger ret = AsnDecoder.ReadInteger(_span, _ruleSet, out int consumed, expectedTag); - _span = _span.Slice(consumed); - return ret; - } - - internal bool TryReadInt32(out int value, Asn1Tag? expectedTag = default) - { - bool ret = AsnDecoder.TryReadInt32(_span, _ruleSet, out value, out int consumed, expectedTag); - _span = _span.Slice(consumed); - return ret; - } - - internal ReadOnlySpan ReadIntegerBytes(Asn1Tag? expectedTag = default) - { - ReadOnlySpan ret = AsnDecoder.ReadIntegerBytes(_span, _ruleSet, out int consumed, expectedTag); - _span = _span.Slice(consumed); - return ret; - } - - internal bool TryReadPrimitiveBitString( - out int unusedBitCount, - out ReadOnlySpan value, - Asn1Tag? expectedTag = default) - { - bool ret = AsnDecoder.TryReadPrimitiveBitString( - _span, - _ruleSet, - out unusedBitCount, - out value, - out int consumed, - expectedTag); - - _span = _span.Slice(consumed); - return ret; - } - - internal byte[] ReadBitString(out int unusedBitCount, Asn1Tag? expectedTag = default) - { - byte[] ret = AsnDecoder.ReadBitString( - _span, - _ruleSet, - out unusedBitCount, - out int consumed, - expectedTag); - - _span = _span.Slice(consumed); - return ret; - } - - internal TFlagsEnum ReadNamedBitListValue(Asn1Tag? expectedTag = default) where TFlagsEnum : Enum - { - TFlagsEnum ret = AsnDecoder.ReadNamedBitListValue(_span, _ruleSet, out int consumed, expectedTag); - _span = _span.Slice(consumed); - return ret; - } - - internal bool TryReadPrimitiveOctetString( - out ReadOnlySpan value, - Asn1Tag? expectedTag = default) - { - bool ret = AsnDecoder.TryReadPrimitiveOctetString( - _span, - _ruleSet, - out value, - out int consumed, - expectedTag); - - _span = _span.Slice(consumed); - return ret; - } - - internal byte[] ReadOctetString(Asn1Tag? expectedTag = default) - { - byte[] ret = AsnDecoder.ReadOctetString( - _span, - _ruleSet, - out int consumed, - expectedTag); - - _span = _span.Slice(consumed); - return ret; - } - - internal string ReadObjectIdentifier(Asn1Tag? expectedTag = default) - { - string ret = AsnDecoder.ReadObjectIdentifier(_span, _ruleSet, out int consumed, expectedTag); - _span = _span.Slice(consumed); - return ret; - } - - internal AsnValueReader ReadSequence(Asn1Tag? expectedTag = default) - { - AsnDecoder.ReadSequence( - _span, - _ruleSet, - out int contentOffset, - out int contentLength, - out int bytesConsumed, - expectedTag); - - ReadOnlySpan content = _span.Slice(contentOffset, contentLength); - _span = _span.Slice(bytesConsumed); - return new AsnValueReader(content, _ruleSet); - } - - internal AsnValueReader ReadSetOf(Asn1Tag? expectedTag = default, bool skipSortOrderValidation = false) - { - AsnDecoder.ReadSetOf( - _span, - _ruleSet, - out int contentOffset, - out int contentLength, - out int bytesConsumed, - skipSortOrderValidation: skipSortOrderValidation, - expectedTag: expectedTag); - - ReadOnlySpan content = _span.Slice(contentOffset, contentLength); - _span = _span.Slice(bytesConsumed); - return new AsnValueReader(content, _ruleSet); - } - - internal DateTimeOffset ReadUtcTime(Asn1Tag? expectedTag = default) - { - DateTimeOffset ret = AsnDecoder.ReadUtcTime(_span, _ruleSet, out int consumed, expectedTag: expectedTag); - _span = _span.Slice(consumed); - return ret; - } - - internal DateTimeOffset ReadGeneralizedTime(Asn1Tag? expectedTag = default) - { - DateTimeOffset ret = AsnDecoder.ReadGeneralizedTime(_span, _ruleSet, out int consumed, expectedTag); - _span = _span.Slice(consumed); - return ret; - } - - internal string ReadCharacterString(UniversalTagNumber encodingType, Asn1Tag? expectedTag = default) - { - string ret = AsnDecoder.ReadCharacterString(_span, _ruleSet, encodingType, out int consumed, expectedTag); - _span = _span.Slice(consumed); - return ret; - } - - internal TEnum ReadEnumeratedValue(Asn1Tag? expectedTag = null) where TEnum : Enum - { - TEnum ret = AsnDecoder.ReadEnumeratedValue(_span, _ruleSet, out int consumed, expectedTag); - _span = _span.Slice(consumed); - return ret; - } - } - - internal static class AsnWriterExtensions - { - internal static void WriteEncodedValueForCrypto( - this AsnWriter writer, - ReadOnlySpan value) - { - try - { - writer.WriteEncodedValue(value); - } - catch (ArgumentException e) - { - throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e); - } - } - - internal static void WriteObjectIdentifierForCrypto( - this AsnWriter writer, - string value) - { - try - { - writer.WriteObjectIdentifier(value); - } - catch (ArgumentException e) - { - throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e); - } - } - - internal static ArraySegment RentAndEncode(this AsnWriter writer) - { - byte[] rented = CryptoPool.Rent(writer.GetEncodedLength()); - int written = writer.Encode(rented); - return new ArraySegment(rented, 0, written); - } - } -} diff --git a/src/libraries/Common/src/System/Security/Cryptography/AsnWriter/AsnWriterExtensions.cs b/src/libraries/Common/src/System/Security/Cryptography/AsnWriter/AsnWriterExtensions.cs new file mode 100644 index 00000000000000..24e659930319af --- /dev/null +++ b/src/libraries/Common/src/System/Security/Cryptography/AsnWriter/AsnWriterExtensions.cs @@ -0,0 +1,38 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Security.Cryptography; + +namespace System.Formats.Asn1 +{ + internal static class AsnWriterExtensions + { + internal static void WriteEncodedValueForCrypto( + this AsnWriter writer, + ReadOnlySpan value) + { + try + { + writer.WriteEncodedValue(value); + } + catch (ArgumentException e) + { + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e); + } + } + + internal static void WriteObjectIdentifierForCrypto( + this AsnWriter writer, + string value) + { + try + { + writer.WriteObjectIdentifier(value); + } + catch (ArgumentException e) + { + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e); + } + } + } +} diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1Reader/System.Security.Cryptography.Asn1Reader.Shared.projitems b/src/libraries/Common/src/System/Security/Cryptography/AsnWriter/System.Security.Cryptography.AsnWriter.Shared.projitems similarity index 66% rename from src/libraries/Common/src/System/Security/Cryptography/Asn1Reader/System.Security.Cryptography.Asn1Reader.Shared.projitems rename to src/libraries/Common/src/System/Security/Cryptography/AsnWriter/System.Security.Cryptography.AsnWriter.Shared.projitems index 518a8c66f4b6b8..2ebe3a4c150ab7 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1Reader/System.Security.Cryptography.Asn1Reader.Shared.projitems +++ b/src/libraries/Common/src/System/Security/Cryptography/AsnWriter/System.Security.Cryptography.AsnWriter.Shared.projitems @@ -9,8 +9,8 @@ - - Common\System\Security\Cryptography\Asn1Reader\AsnValueReader.cs + + Common\System\Security\Cryptography\AsnWriter\AsnWriterExtensions.cs diff --git a/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs b/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs index 331594af026fc5..4c69763709e631 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs @@ -453,30 +453,18 @@ public override void ImportParameters(RSAParameters parameters) if (parameters.D != null) { AsnWriter writer = RSAKeyFormatHelper.WritePkcs8PrivateKey(parameters); - ArraySegment pkcs8 = writer.RentAndEncode(); - - try - { - ImportPkcs8PrivateKey(pkcs8, checkAlgorithm: false, out _); - } - finally + writer.Encode(this, static (RSAOpenSsl rsa, ReadOnlySpan pkcs8) => { - CryptoPool.Return(pkcs8); - } + rsa.ImportPkcs8PrivateKey(pkcs8, checkAlgorithm: false, out _); + }); } else { AsnWriter writer = RSAKeyFormatHelper.WriteSubjectPublicKeyInfo(parameters); - ArraySegment spki = writer.RentAndEncode(); - - try + writer.Encode(this, static (RSAOpenSsl rsa, ReadOnlySpan spki) => { - ImportSubjectPublicKeyInfo(spki, checkAlgorithm: false, out _); - } - finally - { - CryptoPool.Return(spki); - } + rsa.ImportSubjectPublicKeyInfo(spki, checkAlgorithm: false, out _); + }); } } @@ -501,16 +489,10 @@ public override void ImportRSAPublicKey(ReadOnlySpan source, out int bytes } AsnWriter writer = RSAKeyFormatHelper.WriteSubjectPublicKeyInfo(source.Slice(0, read)); - ArraySegment spki = writer.RentAndEncode(); - - try - { - ImportSubjectPublicKeyInfo(spki, checkAlgorithm: false, out _); - } - finally + writer.Encode(this, static (RSAOpenSsl rsa, ReadOnlySpan spki) => { - CryptoPool.Return(spki); - } + rsa.ImportSubjectPublicKeyInfo(spki, checkAlgorithm: false, out _); + }); bytesRead = read; } @@ -617,16 +599,11 @@ public override void ImportRSAPrivateKey(ReadOnlySpan source, out int byte } AsnWriter writer = RSAKeyFormatHelper.WritePkcs8PrivateKey(source.Slice(0, read)); - ArraySegment pkcs8 = writer.RentAndEncode(); - try + writer.Encode(this, static (RSAOpenSsl rsa, ReadOnlySpan pkcs8) => { - ImportPkcs8PrivateKey(pkcs8, checkAlgorithm: false, out _); - } - finally - { - CryptoPool.Return(pkcs8); - } + rsa.ImportPkcs8PrivateKey(pkcs8, checkAlgorithm: false, out _); + }); bytesRead = read; } diff --git a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/CompositeMLDsa/CompositeMLDsaTestHelpers.cs b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/CompositeMLDsa/CompositeMLDsaTestHelpers.cs index 1a1622f3a2bc8c..3ccadf5a25a89e 100644 --- a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/CompositeMLDsa/CompositeMLDsaTestHelpers.cs +++ b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/CompositeMLDsa/CompositeMLDsaTestHelpers.cs @@ -563,8 +563,8 @@ private static RSAParameters RSAParametersFromRawPrivateKey(ReadOnlySpan k { RSAParameters parameters = default; - AsnValueReader reader = new AsnValueReader(key, AsnEncodingRules.BER); - AsnValueReader sequenceReader = reader.ReadSequence(Asn1Tag.Sequence); + ValueAsnReader reader = new ValueAsnReader(key, AsnEncodingRules.BER); + ValueAsnReader sequenceReader = reader.ReadSequence(Asn1Tag.Sequence); if (!sequenceReader.TryReadInt32(out int version)) { diff --git a/src/libraries/Microsoft.Bcl.Cryptography/src/Microsoft.Bcl.Cryptography.csproj b/src/libraries/Microsoft.Bcl.Cryptography/src/Microsoft.Bcl.Cryptography.csproj index aeae1c55ea7cc0..6670adf751a160 100644 --- a/src/libraries/Microsoft.Bcl.Cryptography/src/Microsoft.Bcl.Cryptography.csproj +++ b/src/libraries/Microsoft.Bcl.Cryptography/src/Microsoft.Bcl.Cryptography.csproj @@ -21,7 +21,7 @@ - + - + ? Diagnostics { get; private set; } + public List? Diagnostics { get; private set; } public SourceGenerationSpec? GetSourceGenerationSpec(ImmutableArray invocations, CancellationToken cancellationToken) { if (!_langVersionIsSupported) { - RecordDiagnostic(DiagnosticDescriptors.LanguageVersionNotSupported, trimmedLocation: Location.None); + RecordDiagnostic(DiagnosticDescriptors.LanguageVersionNotSupported, location: Location.None); return null; } @@ -979,10 +979,10 @@ private void ReportContainingTypeDiagnosticIfRequired(TypeParseInfo typeParseInf } } - private void RecordDiagnostic(DiagnosticDescriptor descriptor, Location trimmedLocation, params object?[]? messageArgs) + private void RecordDiagnostic(DiagnosticDescriptor descriptor, Location location, params object?[]? messageArgs) { - Diagnostics ??= new List(); - Diagnostics.Add(DiagnosticInfo.Create(descriptor, trimmedLocation, messageArgs)); + Diagnostics ??= new List(); + Diagnostics.Add(Diagnostic.Create(descriptor, location, messageArgs)); } private void CheckIfToEmitParseEnumMethod() diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.cs index 4a3d5bbf7dea81..816bdff43f5c40 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.cs @@ -6,10 +6,10 @@ using System.Diagnostics; using System.Reflection; using System.Threading; +using System.Collections.Immutable; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; -using SourceGenerators; namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { @@ -37,7 +37,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) ? new CompilationData((CSharpCompilation)compilation) : null); - IncrementalValueProvider<(SourceGenerationSpec?, ImmutableEquatableArray?)> genSpec = context.SyntaxProvider + IncrementalValueProvider<(SourceGenerationSpec?, ImmutableArray)> genSpec = context.SyntaxProvider .CreateSyntaxProvider( (node, _) => BinderInvocation.IsCandidateSyntaxNode(node), BinderInvocation.Create) @@ -48,14 +48,16 @@ public void Initialize(IncrementalGeneratorInitializationContext context) { if (tuple.Right is not CompilationData compilationData) { - return (null, null); + return (null, ImmutableArray.Empty); } try { Parser parser = new(compilationData); SourceGenerationSpec? spec = parser.GetSourceGenerationSpec(tuple.Left, cancellationToken); - ImmutableEquatableArray? diagnostics = parser.Diagnostics?.ToImmutableEquatableArray(); + ImmutableArray diagnostics = parser.Diagnostics is { } diags + ? diags.ToImmutableArray() + : ImmutableArray.Empty; return (spec, diagnostics); } catch (Exception ex) @@ -65,7 +67,26 @@ public void Initialize(IncrementalGeneratorInitializationContext context) }) .WithTrackingName(GenSpecTrackingName); - context.RegisterSourceOutput(genSpec, ReportDiagnosticsAndEmitSource); + // Project the combined pipeline result to just the equatable model, discarding diagnostics. + // SourceGenerationSpec implements value equality, so Roslyn's Select operator will compare + // successive model snapshots and only propagate changes downstream when the model structurally + // differs. This ensures source generation is fully incremental: re-emitting code only when + // the binding spec actually changes, not on every keystroke or positional shift. + IncrementalValueProvider sourceGenerationSpec = + genSpec.Select(static (t, _) => t.Item1); + + context.RegisterSourceOutput(sourceGenerationSpec, EmitSource); + + // Project to just the diagnostics, discarding the model. ImmutableArray does not + // implement value equality, so Roslyn's incremental pipeline uses reference equality for these + // values — the callback fires on every compilation change. This is by design: diagnostic + // emission is cheap, and we need fresh SourceLocation instances that are pragma-suppressible + // (cf. https://github.com/dotnet/runtime/issues/92509). + // No source code is generated from this pipeline — it exists solely to report diagnostics. + IncrementalValueProvider> diagnostics = + genSpec.Select(static (t, _) => t.Item2); + + context.RegisterSourceOutput(diagnostics, EmitDiagnostics); if (!s_hasInitializedInterceptorVersion) { @@ -136,17 +157,17 @@ internal static int DetermineInterceptableVersion() /// public Action? OnSourceEmitting { get; init; } - private void ReportDiagnosticsAndEmitSource(SourceProductionContext sourceProductionContext, (SourceGenerationSpec? SourceGenerationSpec, ImmutableEquatableArray? Diagnostics) input) + private static void EmitDiagnostics(SourceProductionContext context, ImmutableArray diagnostics) { - if (input.Diagnostics is ImmutableEquatableArray diagnostics) + foreach (Diagnostic diagnostic in diagnostics) { - foreach (DiagnosticInfo diagnostic in diagnostics) - { - sourceProductionContext.ReportDiagnostic(diagnostic.CreateDiagnostic()); - } + context.ReportDiagnostic(diagnostic); } + } - if (input.SourceGenerationSpec is SourceGenerationSpec spec) + private void EmitSource(SourceProductionContext sourceProductionContext, SourceGenerationSpec? spec) + { + if (spec is not null) { OnSourceEmitting?.Invoke(spec); Emitter emitter = new(spec); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Microsoft.Extensions.Configuration.Binder.SourceGeneration.csproj b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Microsoft.Extensions.Configuration.Binder.SourceGeneration.csproj index bf12a1fc225b81..a0fac6dbbfb626 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Microsoft.Extensions.Configuration.Binder.SourceGeneration.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Microsoft.Extensions.Configuration.Binder.SourceGeneration.csproj @@ -30,7 +30,6 @@ - diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.cs index 7eee48fdeb28ca..e15f9625a971a1 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.cs @@ -12,6 +12,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; @@ -414,5 +415,129 @@ public class AnotherGraphWithUnsupportedMembers Assert.True(result.Diagnostics.Any(diag => diag.Id == Diagnostics.TypeNotSupported.Id)); Assert.True(result.Diagnostics.Any(diag => diag.Id == Diagnostics.PropertyNotSupported.Id)); } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] + public async Task Diagnostic_HasPragmaSuppressibleLocation() + { + // SYSLIB1103: ValueTypesInvalidForBind (Warning, configurable). + string source = """ + #pragma warning disable SYSLIB1103 + using System; + using Microsoft.Extensions.Configuration; + + public class Program + { + public static void Main() + { + ConfigurationBuilder configurationBuilder = new(); + IConfigurationRoot config = configurationBuilder.Build(); + + int myInt = 1; + config.Bind(myInt); + } + } + """; + + ConfigBindingGenRunResult result = await RunGeneratorAndUpdateCompilation(source); + var effective = CompilationWithAnalyzers.GetEffectiveDiagnostics(result.Diagnostics, result.OutputCompilation); + Diagnostic diagnostic = Assert.Single(effective, d => d.Id == "SYSLIB1103"); + Assert.True(diagnostic.IsSuppressed); + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] + public async Task Diagnostic_NoPragma_IsNotSuppressed() + { + string source = """ + using System; + using Microsoft.Extensions.Configuration; + + public class Program + { + public static void Main() + { + ConfigurationBuilder configurationBuilder = new(); + IConfigurationRoot config = configurationBuilder.Build(); + + int myInt = 1; + config.Bind(myInt); + } + } + """; + + ConfigBindingGenRunResult result = await RunGeneratorAndUpdateCompilation(source); + var effective = CompilationWithAnalyzers.GetEffectiveDiagnostics(result.Diagnostics, result.OutputCompilation); + Diagnostic diagnostic = Assert.Single(effective, d => d.Id == "SYSLIB1103"); + Assert.False(diagnostic.IsSuppressed); + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] + public async Task Diagnostic_MultipleDiagnostics_OnlySomeSuppressed() + { + string source = """ + using System; + using System.Collections.Immutable; + using System.Text; + using System.Text.Json; + using Microsoft.Extensions.Configuration; + + public class Program + { + public static void Main() + { + ConfigurationBuilder configurationBuilder = new(); + IConfigurationRoot config = configurationBuilder.Build(); + + // SYSLIB1103 suppressed for this call only. + #pragma warning disable SYSLIB1103 + int myInt = 1; + config.Bind(myInt); + #pragma warning restore SYSLIB1103 + + // SYSLIB1103 NOT suppressed for this call. + long myLong = 1; + config.Bind(myLong); + } + } + """; + + ConfigBindingGenRunResult result = await RunGeneratorAndUpdateCompilation(source); + var effective = CompilationWithAnalyzers.GetEffectiveDiagnostics(result.Diagnostics, result.OutputCompilation) + .Where(d => d.Id == "SYSLIB1103") + .ToList(); + + Assert.Equal(2, effective.Count); + Assert.Single(effective, d => d.IsSuppressed); + Assert.Single(effective, d => !d.IsSuppressed); + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] + public async Task Diagnostic_PragmaRestoreOutsideSpan_IsNotSuppressed() + { + string source = """ + using System; + using Microsoft.Extensions.Configuration; + + public class Program + { + public static void Main() + { + ConfigurationBuilder configurationBuilder = new(); + IConfigurationRoot config = configurationBuilder.Build(); + + // Suppress and restore BEFORE the diagnostic site. + #pragma warning disable SYSLIB1103 + #pragma warning restore SYSLIB1103 + + int myInt = 1; + config.Bind(myInt); + } + } + """; + + ConfigBindingGenRunResult result = await RunGeneratorAndUpdateCompilation(source); + var effective = CompilationWithAnalyzers.GetEffectiveDiagnostics(result.Diagnostics, result.OutputCompilation); + Diagnostic diagnostic = Assert.Single(effective, d => d.Id == "SYSLIB1103"); + Assert.False(diagnostic.IsSuppressed); + } } } diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/LoggerMessageGenerator.Parser.cs b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/LoggerMessageGenerator.Parser.cs index c69c2db2c07e85..b98abaf7d04c99 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/LoggerMessageGenerator.Parser.cs +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/LoggerMessageGenerator.Parser.cs @@ -38,7 +38,7 @@ internal sealed class Parser private readonly INamedTypeSymbol _stringSymbol; private readonly Action? _reportDiagnostic; - public List Diagnostics { get; } = new(); + public List Diagnostics { get; } = new(); public Parser( INamedTypeSymbol loggerMessageAttribute, @@ -811,12 +811,14 @@ private static string GenerateClassName(TypeDeclarationSyntax typeDeclaration) private void Diag(DiagnosticDescriptor desc, Location? location, params object?[]? messageArgs) { + Diagnostic diagnostic = Diagnostic.Create(desc, location, messageArgs); + // Report immediately if callback is provided (preserves pragma suppression with original locations) - _reportDiagnostic?.Invoke(Diagnostic.Create(desc, location, messageArgs)); + _reportDiagnostic?.Invoke(diagnostic); // Also collect for scenarios that need the diagnostics list; in Roslyn 4.0+ incremental generators, - // this list is exposed via parser.Diagnostics (as ImmutableEquatableArray) and reported in Execute. - Diagnostics.Add(DiagnosticInfo.Create(desc, location, messageArgs)); + // this list is exposed via parser.Diagnostics and reported in the diagnostic pipeline. + Diagnostics.Add(diagnostic); } private static bool IsBaseOrIdentity(ITypeSymbol source, ITypeSymbol dest, Compilation compilation) diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/LoggerMessageGenerator.Roslyn4.0.cs b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/LoggerMessageGenerator.Roslyn4.0.cs index ef9fa6582b53b3..9a205f873a6d00 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/LoggerMessageGenerator.Roslyn4.0.cs +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/LoggerMessageGenerator.Roslyn4.0.cs @@ -25,7 +25,7 @@ public static class StepNames public void Initialize(IncrementalGeneratorInitializationContext context) { - IncrementalValuesProvider<(LoggerClassSpec? LoggerClassSpec, ImmutableEquatableArray Diagnostics, bool HasStringCreate)> loggerClasses = context.SyntaxProvider + IncrementalValuesProvider<(LoggerClassSpec? LoggerClassSpec, ImmutableArray Diagnostics, bool HasStringCreate)> loggerClasses = context.SyntaxProvider .ForAttributeWithMetadataName( #if !ROSLYN4_4_OR_GREATER context, @@ -66,7 +66,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) if (exceptionSymbol == null) { - var diagnostics = new[] { DiagnosticInfo.Create(DiagnosticDescriptors.MissingRequiredType, null, new object?[] { "System.Exception" }) }.ToImmutableEquatableArray(); + var diagnostics = ImmutableArray.Create(Diagnostic.Create(DiagnosticDescriptors.MissingRequiredType, null, new object?[] { "System.Exception" })); return (null, diagnostics, false); } @@ -92,75 +92,110 @@ public void Initialize(IncrementalGeneratorInitializationContext context) // Convert to immutable spec for incremental caching LoggerClassSpec? loggerClassSpec = logClasses.Count > 0 ? logClasses[0].ToSpec() : null; - return (loggerClassSpec, parser.Diagnostics.ToImmutableEquatableArray(), hasStringCreate); + return (loggerClassSpec, parser.Diagnostics.ToImmutableArray(), hasStringCreate); }) #if ROSLYN4_4_OR_GREATER .WithTrackingName(StepNames.LoggerMessageTransform) #endif ; - context.RegisterSourceOutput(loggerClasses.Collect(), static (spc, items) => Execute(items, spc)); + // Single collect for all per-method results, then aggregate into an equatable source + // model (using ImmutableEquatableArray for deep value equality) plus flat diagnostics. + // Diagnostics are deduplicated here because each attributed method triggers parsing of + // the entire class, producing duplicate diagnostics. + IncrementalValueProvider<(ImmutableEquatableArray<(LoggerClassSpec LoggerClassSpec, bool HasStringCreate)> Specs, ImmutableArray Diagnostics)> collected = + loggerClasses.Collect().Select(static (items, _) => + { + ImmutableArray<(LoggerClassSpec, bool)>.Builder? specs = null; + ImmutableArray.Builder? diagnostics = null; + HashSet<(string Id, TextSpan? Span, string? FilePath, string Message)>? seen = null; + + foreach (var item in items) + { + if (item.LoggerClassSpec is not null) + { + (specs ??= ImmutableArray.CreateBuilder<(LoggerClassSpec, bool)>()).Add((item.LoggerClassSpec, item.HasStringCreate)); + } + foreach (Diagnostic diagnostic in item.Diagnostics) + { + if ((seen ??= new()).Add((diagnostic.Id, diagnostic.Location?.SourceSpan, diagnostic.Location?.SourceTree?.FilePath, diagnostic.GetMessage()))) + { + (diagnostics ??= ImmutableArray.CreateBuilder()).Add(diagnostic); + } + } + } + + return ( + specs?.ToImmutableEquatableArray() ?? ImmutableEquatableArray<(LoggerClassSpec, bool)>.Empty, + diagnostics?.ToImmutable() ?? ImmutableArray.Empty); + }); + + // Project to just the equatable source model, discarding diagnostics. + // ImmutableEquatableArray provides deep value equality, so Roslyn's Select operator + // compares successive model snapshots and only propagates changes downstream when the + // model structurally differs. This ensures source generation is fully incremental. + IncrementalValueProvider> sourceGenerationSpecs = + collected.Select(static (t, _) => t.Specs); + + context.RegisterSourceOutput(sourceGenerationSpecs, static (spc, items) => EmitSource(items, spc)); + + // Project to just the diagnostics, discarding the model. ImmutableArray does not + // implement value equality, so Roslyn's incremental pipeline uses reference equality for these + // values — the callback fires on every compilation change. This is by design: diagnostic + // emission is cheap, and we need fresh SourceLocation instances that are pragma-suppressible + // (cf. https://github.com/dotnet/runtime/issues/92509). + IncrementalValueProvider> diagnosticResults = + collected.Select(static (t, _) => t.Diagnostics); + + context.RegisterSourceOutput(diagnosticResults, EmitDiagnostics); + } + + private static void EmitDiagnostics(SourceProductionContext context, ImmutableArray diagnostics) + { + foreach (Diagnostic diagnostic in diagnostics) + { + context.ReportDiagnostic(diagnostic); + } } - private static void Execute(ImmutableArray<(LoggerClassSpec? LoggerClassSpec, ImmutableEquatableArray Diagnostics, bool HasStringCreate)> items, SourceProductionContext context) + private static void EmitSource(ImmutableEquatableArray<(LoggerClassSpec LoggerClassSpec, bool HasStringCreate)> items, SourceProductionContext context) { - if (items.IsDefaultOrEmpty) + if (items.Count == 0) { return; } bool hasStringCreate = false; - var allLogClasses = new Dictionary(); // Use dictionary to deduplicate by class key - var reportedDiagnostics = new HashSet(); // Track reported diagnostics to avoid duplicates + var allLogClasses = new Dictionary(); // Deduplicate by class key foreach (var item in items) { - // Report diagnostics (note: pragma suppression doesn't work with trimmed locations - known Roslyn limitation) - // Use HashSet to deduplicate - each attributed method triggers parsing of entire class, producing duplicate diagnostics - if (item.Diagnostics is not null) + hasStringCreate |= item.HasStringCreate; + + // Build unique key including parent class chain to handle nested classes + string classKey = BuildClassKey(item.LoggerClassSpec); + + // Each attributed method in a partial class file produces the same LoggerClassSpec with all methods in that file. + // However, different partial class files produce different LoggerClassSpecs with different methods. Merge them. + if (!allLogClasses.TryGetValue(classKey, out LoggerClass? existingClass)) { - foreach (var diagnostic in item.Diagnostics) - { - if (reportedDiagnostics.Add(diagnostic)) - { - context.ReportDiagnostic(diagnostic.CreateDiagnostic()); - } - } + allLogClasses[classKey] = FromSpec(item.LoggerClassSpec); } - - if (item.LoggerClassSpec != null) + else { - hasStringCreate |= item.HasStringCreate; - - // Build unique key including parent class chain to handle nested classes - string classKey = BuildClassKey(item.LoggerClassSpec); + var newClass = FromSpec(item.LoggerClassSpec); - // Each attributed method in a partial class file produces the same LoggerClassSpec with all methods in that file. - // However, different partial class files (e.g., LevelTestExtensions.cs and LevelTestExtensions.WithDiagnostics.cs) - // produce different LoggerClassSpecs with different methods. Merge them. - if (!allLogClasses.TryGetValue(classKey, out LoggerClass? existingClass)) + var existingMethodKeys = new HashSet<(string Name, int EventId)>(); + foreach (var method in existingClass.Methods) { - allLogClasses[classKey] = FromSpec(item.LoggerClassSpec); + existingMethodKeys.Add((method.Name, method.EventId)); } - else - { - // Merge methods from different partial class files - var newClass = FromSpec(item.LoggerClassSpec); - - // Use HashSet for O(1) lookup to avoid O(N×M) complexity - var existingMethodKeys = new HashSet<(string Name, int EventId)>(); - foreach (var method in existingClass.Methods) - { - existingMethodKeys.Add((method.Name, method.EventId)); - } - foreach (var method in newClass.Methods) + foreach (var method in newClass.Methods) + { + if (existingMethodKeys.Add((method.Name, method.EventId))) { - // Only add methods that don't already exist (avoid duplicates from same file) - if (existingMethodKeys.Add((method.Name, method.EventId))) - { - existingClass.Methods.Add(method); - } + existingClass.Methods.Add(method); } } } diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Microsoft.Extensions.Logging.Generators.targets b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Microsoft.Extensions.Logging.Generators.targets index f1a42f8831ecfa..096dc2f89a3709 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Microsoft.Extensions.Logging.Generators.targets +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Microsoft.Extensions.Logging.Generators.targets @@ -25,7 +25,6 @@ - diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratorParserTests.cs b/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratorParserTests.cs index a6cc6db209297d..a6bef486f6de2f 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratorParserTests.cs +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratorParserTests.cs @@ -10,6 +10,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Diagnostics; using SourceGenerators.Tests; using Xunit; @@ -1426,5 +1427,35 @@ private static async Task> RunGenerator( return d; } + + [Fact] + public async Task Diagnostic_HasPragmaSuppressibleLocation() + { + // SYSLIB1017: MissingLogLevel (Error, but not NotConfigurable). + string code = """ + #pragma warning disable SYSLIB1017 + using Microsoft.Extensions.Logging; + + namespace Test + { + partial class C + { + [LoggerMessage(EventId = 0, Message = "M1")] + static partial void M1(ILogger logger); + } + } + """; + + Assembly[] refs = new[] { typeof(ILogger).Assembly, typeof(LoggerMessageAttribute).Assembly }; + using var workspace = RoslynTestUtils.CreateTestWorkspace(); + Project proj = RoslynTestUtils.CreateTestProject(workspace, refs) + .WithDocuments(new[] { code }); + Assert.True(proj.Solution.Workspace.TryApplyChanges(proj.Solution)); + Compilation comp = (await proj.GetCompilationAsync().ConfigureAwait(false))!; + var (diags, _) = RoslynTestUtils.RunGenerator(comp, new LoggerMessageGenerator()); + var effective = CompilationWithAnalyzers.GetEffectiveDiagnostics(diags, comp); + Diagnostic diagnostic = Assert.Single(effective, d => d.Id == "SYSLIB1017"); + Assert.True(diagnostic.IsSuppressed); + } } } diff --git a/src/libraries/System.Net.Ping/src/System/Net/NetworkInformation/Ping.Windows.cs b/src/libraries/System.Net.Ping/src/System/Net/NetworkInformation/Ping.Windows.cs index 0b04636ac4f71c..d63c19b44d44d2 100644 --- a/src/libraries/System.Net.Ping/src/System/Net/NetworkInformation/Ping.Windows.cs +++ b/src/libraries/System.Net.Ping/src/System/Net/NetworkInformation/Ping.Windows.cs @@ -344,21 +344,21 @@ private static PingReply CreatePingReplyFromIcmpEchoReply(in Interop.IpHlpApi.IC IPAddress address = new IPAddress(reply.address); IPStatus ipStatus = GetStatusFromCode((int)reply.status); - long rtt; + // The ICMP_ECHO_REPLY RoundTripTime field is always populated by the OS + // for any received reply, regardless of status (e.g. TTL expired, unreachable). + long rtt = reply.roundTripTime; PingOptions? options; byte[] buffer; if (ipStatus == IPStatus.Success) { // Only copy the data if we succeed w/ the ping operation. - rtt = reply.roundTripTime; options = new PingOptions(reply.options.ttl, (reply.options.flags & DontFragmentFlag) > 0); buffer = new byte[reply.dataSize]; Marshal.Copy(reply.data, buffer, 0, reply.dataSize); } else { - rtt = 0; options = null; buffer = Array.Empty(); } @@ -371,19 +371,19 @@ private static PingReply CreatePingReplyFromIcmp6EchoReply(in Interop.IpHlpApi.I IPAddress address = new IPAddress(reply.Address.Address, reply.Address.ScopeID); IPStatus ipStatus = GetStatusFromCode((int)reply.Status); - long rtt; + // The ICMPV6_ECHO_REPLY RoundTripTime field is always populated by the OS + // for any received reply, regardless of status (e.g. TTL expired, unreachable). + long rtt = reply.RoundTripTime; byte[] buffer; if (ipStatus == IPStatus.Success) { // Only copy the data if we succeed w/ the ping operation. - rtt = reply.RoundTripTime; buffer = new byte[sendSize]; Marshal.Copy(dataPtr + 36, buffer, 0, sendSize); } else { - rtt = 0; buffer = Array.Empty(); } diff --git a/src/libraries/System.Net.Ping/tests/FunctionalTests/PingTest.cs b/src/libraries/System.Net.Ping/tests/FunctionalTests/PingTest.cs index 5265b001010ec9..900302a3fa9517 100644 --- a/src/libraries/System.Net.Ping/tests/FunctionalTests/PingTest.cs +++ b/src/libraries/System.Net.Ping/tests/FunctionalTests/PingTest.cs @@ -787,6 +787,62 @@ public async Task SendPingToExternalHostWithLowTtlTest() Assert.NotEqual(IPAddress.Any, pingReply.Address); } + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsMultithreadingSupported))] + [OuterLoop] // Depends on external host + public async Task SendPingWithLowTtl_RoundtripTimeIsNonZero() + { + // Regression test: non-Success replies (e.g. TtlExpired) should preserve the + // round-trip time from the ICMP reply, not hardcode it to 0. + if (UsesPingUtility) + { + throw new SkipTestException("Test is only applicable to the IcmpSendEcho code path."); + } + + string host = System.Net.Test.Common.Configuration.Ping.PingHost; + PingOptions options = new PingOptions(); + byte[] payload = TestSettings.PayloadAsBytesShort; + + using Ping ping = new Ping(); + + // Verify host is reachable first. + bool reachable = false; + for (int i = 0; i < s_pingcount; i++) + { + PingReply checkReply = await ping.SendPingAsync(host, TestSettings.PingTimeout, payload); + if (checkReply.Status == IPStatus.Success) + { + reachable = true; + break; + } + } + if (!reachable) + { + throw new SkipTestException($"Host {host} is not reachable. Skipping test."); + } + + // RTT can legitimately be 0ms on very fast networks, so retry a few times + // and assert that at least one reply reports a non-zero RTT. + options.Ttl = 1; + bool gotNonZeroRtt = false; + for (int attempt = 0; attempt < 3; attempt++) + { + PingReply pingReply = await ping.SendPingAsync(host, TestSettings.PingTimeout, payload, options); + + Assert.True( + pingReply.Status == IPStatus.TimeExceeded || pingReply.Status == IPStatus.TtlExpired, + $"pingReply.Status was {pingReply.Status} instead of TimeExceeded or TtlExpired"); + + if (pingReply.RoundtripTime > 0) + { + gotNonZeroRtt = true; + break; + } + } + + Assert.True(gotNonZeroRtt, + "Expected at least one TtlExpired reply with non-zero RoundtripTime across 3 attempts"); + } + private async Task Ping_TimedOut_Core(Func> sendPing) { Ping sender = new Ping(); diff --git a/src/libraries/System.Net.Security/src/System.Net.Security.csproj b/src/libraries/System.Net.Security/src/System.Net.Security.csproj index fa9f8b24212436..61d4b05c9aae6b 100644 --- a/src/libraries/System.Net.Security/src/System.Net.Security.csproj +++ b/src/libraries/System.Net.Security/src/System.Net.Security.csproj @@ -23,8 +23,6 @@ ReferenceAssemblyExclusions.txt - - diff --git a/src/libraries/System.Net.Security/src/System/Net/NegotiateAuthenticationPal.ManagedSpnego.cs b/src/libraries/System.Net.Security/src/System/Net/NegotiateAuthenticationPal.ManagedSpnego.cs index 1ddb004769037f..ad860ec7595f5b 100644 --- a/src/libraries/System.Net.Security/src/System/Net/NegotiateAuthenticationPal.ManagedSpnego.cs +++ b/src/libraries/System.Net.Security/src/System/Net/NegotiateAuthenticationPal.ManagedSpnego.cs @@ -222,8 +222,8 @@ private IEnumerable> EnumerateMechanisms() try { - AsnValueReader reader = new AsnValueReader(challenge, AsnEncodingRules.DER); - AsnValueReader challengeReader = reader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, (int)NegotiationToken.NegTokenResp)); + ValueAsnReader reader = new ValueAsnReader(challenge, AsnEncodingRules.DER); + ValueAsnReader challengeReader = reader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, (int)NegotiationToken.NegTokenResp)); reader.ThrowIfNotEmpty(); // NegTokenResp ::= SEQUENCE { @@ -245,28 +245,28 @@ private IEnumerable> EnumerateMechanisms() if (challengeReader.HasData && challengeReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, (int)NegTokenResp.NegState))) { - AsnValueReader valueReader = challengeReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, (int)NegTokenResp.NegState)); + ValueAsnReader valueReader = challengeReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, (int)NegTokenResp.NegState)); state = valueReader.ReadEnumeratedValue(); valueReader.ThrowIfNotEmpty(); } if (challengeReader.HasData && challengeReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, (int)NegTokenResp.SupportedMech))) { - AsnValueReader valueReader = challengeReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, (int)NegTokenResp.SupportedMech)); + ValueAsnReader valueReader = challengeReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, (int)NegTokenResp.SupportedMech)); mech = valueReader.ReadObjectIdentifier(); valueReader.ThrowIfNotEmpty(); } if (challengeReader.HasData && challengeReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, (int)NegTokenResp.ResponseToken))) { - AsnValueReader valueReader = challengeReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, (int)NegTokenResp.ResponseToken)); + ValueAsnReader valueReader = challengeReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, (int)NegTokenResp.ResponseToken)); blob = valueReader.ReadOctetString(); valueReader.ThrowIfNotEmpty(); } if (challengeReader.HasData && challengeReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, (int)NegTokenResp.MechListMIC))) { - AsnValueReader valueReader = challengeReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, (int)NegTokenResp.MechListMIC)); + ValueAsnReader valueReader = challengeReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, (int)NegTokenResp.MechListMIC)); mechListMIC = valueReader.ReadOctetString(); valueReader.ThrowIfNotEmpty(); } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.PlatformNotSupported.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.PlatformNotSupported.cs index 819b72cec57008..6e013db76ae088 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.PlatformNotSupported.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.PlatformNotSupported.cs @@ -4938,18 +4938,6 @@ internal Arm64() { } // Load 32-bit data and zero-extend - /// - /// svint64_t svld1uw_gather_[s64]offset_s64(svbool_t pg, const uint32_t *base, svint64_t offsets) - /// LD1W Zresult.D, Pg/Z, [Xbase, Zoffsets.D] - /// - public static unsafe Vector GatherVectorUInt32WithByteOffsetsZeroExtend(Vector mask, uint* address, Vector offsets) { throw new PlatformNotSupportedException(); } - - /// - /// svint64_t svld1uw_gather_[u64]offset_s64(svbool_t pg, const uint32_t *base, svuint64_t offsets) - /// LD1W Zresult.D, Pg/Z, [Xbase, Zoffsets.D] - /// - public static unsafe Vector GatherVectorUInt32WithByteOffsetsZeroExtend(Vector mask, uint* address, Vector offsets) { throw new PlatformNotSupportedException(); } - /// /// svint64_t svld1uw_gather_[s64]offset_s64(svbool_t pg, const uint32_t *base, svint64_t offsets) /// LD1W Zresult.D, Pg/Z, [Xbase, Zoffsets.D] @@ -4962,18 +4950,6 @@ internal Arm64() { } /// public static unsafe Vector GatherVectorUInt32WithByteOffsetsZeroExtend(Vector mask, uint* address, Vector offsets) { throw new PlatformNotSupportedException(); } - /// - /// svuint64_t svld1uw_gather_[s64]offset_u64(svbool_t pg, const uint32_t *base, svint64_t offsets) - /// LD1W Zresult.D, Pg/Z, [Xbase, Zoffsets.D] - /// - public static unsafe Vector GatherVectorUInt32WithByteOffsetsZeroExtend(Vector mask, uint* address, Vector offsets) { throw new PlatformNotSupportedException(); } - - /// - /// svuint64_t svld1uw_gather_[u64]offset_u64(svbool_t pg, const uint32_t *base, svuint64_t offsets) - /// LD1W Zresult.D, Pg/Z, [Xbase, Zoffsets.D] - /// - public static unsafe Vector GatherVectorUInt32WithByteOffsetsZeroExtend(Vector mask, uint* address, Vector offsets) { throw new PlatformNotSupportedException(); } - /// /// svuint64_t svld1uw_gather_[s64]offset_u64(svbool_t pg, const uint32_t *base, svint64_t offsets) /// LD1W Zresult.D, Pg/Z, [Xbase, Zoffsets.D] @@ -4989,18 +4965,6 @@ internal Arm64() { } // Load 32-bit data and zero-extend, first-faulting - /// - /// svint64_t svldff1uw_gather_[s64]offset_s64(svbool_t pg, const uint32_t *base, svint64_t offsets) - /// LDFF1W Zresult.D, Pg/Z, [Xbase, Zoffsets.D] - /// - public static unsafe Vector GatherVectorUInt32WithByteOffsetsZeroExtendFirstFaulting(Vector mask, uint* address, Vector offsets) { throw new PlatformNotSupportedException(); } - - /// - /// svint64_t svldff1uw_gather_[u64]offset_s64(svbool_t pg, const uint32_t *base, svuint64_t offsets) - /// LDFF1W Zresult.D, Pg/Z, [Xbase, Zoffsets.D] - /// - public static unsafe Vector GatherVectorUInt32WithByteOffsetsZeroExtendFirstFaulting(Vector mask, uint* address, Vector offsets) { throw new PlatformNotSupportedException(); } - /// /// svint64_t svldff1uw_gather_[s64]offset_s64(svbool_t pg, const uint32_t *base, svint64_t offsets) /// LDFF1W Zresult.D, Pg/Z, [Xbase, Zoffsets.D] @@ -5013,18 +4977,6 @@ internal Arm64() { } /// public static unsafe Vector GatherVectorUInt32WithByteOffsetsZeroExtendFirstFaulting(Vector mask, uint* address, Vector offsets) { throw new PlatformNotSupportedException(); } - /// - /// svuint64_t svldff1uw_gather_[s64]offset_u64(svbool_t pg, const uint32_t *base, svint64_t offsets) - /// LDFF1W Zresult.D, Pg/Z, [Xbase, Zoffsets.D] - /// - public static unsafe Vector GatherVectorUInt32WithByteOffsetsZeroExtendFirstFaulting(Vector mask, uint* address, Vector offsets) { throw new PlatformNotSupportedException(); } - - /// - /// svuint64_t svldff1uw_gather_[u64]offset_u64(svbool_t pg, const uint32_t *base, svuint64_t offsets) - /// LDFF1W Zresult.D, Pg/Z, [Xbase, Zoffsets.D] - /// - public static unsafe Vector GatherVectorUInt32WithByteOffsetsZeroExtendFirstFaulting(Vector mask, uint* address, Vector offsets) { throw new PlatformNotSupportedException(); } - /// /// svuint64_t svldff1uw_gather_[s64]offset_u64(svbool_t pg, const uint32_t *base, svint64_t offsets) /// LDFF1W Zresult.D, Pg/Z, [Xbase, Zoffsets.D] @@ -5040,25 +4992,6 @@ internal Arm64() { } // Load 32-bit data and zero-extend - /// - /// svint64_t svld1uw_gather_[s64]index_s64(svbool_t pg, const uint32_t *base, svint64_t indices) - /// LD1W Zresult.D, Pg/Z, [Xbase, Zindices.D, LSL #2] - /// - public static unsafe Vector GatherVectorUInt32ZeroExtend(Vector mask, uint* address, Vector indices) { throw new PlatformNotSupportedException(); } - - // - // svint64_t svld1uw_gather[_u64base]_s64(svbool_t pg, svuint64_t bases) - // LD1W Zresult.D, Pg/Z, [Zbases.D, #0] - // - // Removed as per #103297 - // public static Vector GatherVectorUInt32ZeroExtend(Vector mask, Vector addresses) { throw new PlatformNotSupportedException(); } - - /// - /// svint64_t svld1uw_gather_[u64]index_s64(svbool_t pg, const uint32_t *base, svuint64_t indices) - /// LD1W Zresult.D, Pg/Z, [Xbase, Zindices.D, LSL #2] - /// - public static unsafe Vector GatherVectorUInt32ZeroExtend(Vector mask, uint* address, Vector indices) { throw new PlatformNotSupportedException(); } - /// /// svint64_t svld1uw_gather_[s64]index_s64(svbool_t pg, const uint32_t *base, svint64_t indices) /// LD1W Zresult.D, Pg/Z, [Xbase, Zindices.D, LSL #2] @@ -5077,25 +5010,6 @@ internal Arm64() { } /// public static unsafe Vector GatherVectorUInt32ZeroExtend(Vector mask, uint* address, Vector indices) { throw new PlatformNotSupportedException(); } - /// - /// svuint64_t svld1uw_gather_[s64]index_u64(svbool_t pg, const uint32_t *base, svint64_t indices) - /// LD1W Zresult.D, Pg/Z, [Xbase, Zindices.D, LSL #2] - /// - public static unsafe Vector GatherVectorUInt32ZeroExtend(Vector mask, uint* address, Vector indices) { throw new PlatformNotSupportedException(); } - - // - // svuint64_t svld1uw_gather[_u64base]_u64(svbool_t pg, svuint64_t bases) - // LD1W Zresult.D, Pg/Z, [Zbases.D, #0] - // - // Removed as per #103297 - // public static Vector GatherVectorUInt32ZeroExtend(Vector mask, Vector addresses) { throw new PlatformNotSupportedException(); } - - /// - /// svuint64_t svld1uw_gather_[u64]index_u64(svbool_t pg, const uint32_t *base, svuint64_t indices) - /// LD1W Zresult.D, Pg/Z, [Xbase, Zindices.D, LSL #2] - /// - public static unsafe Vector GatherVectorUInt32ZeroExtend(Vector mask, uint* address, Vector indices) { throw new PlatformNotSupportedException(); } - /// /// svuint64_t svld1uw_gather_[s64]index_u64(svbool_t pg, const uint32_t *base, svint64_t indices) /// LD1W Zresult.D, Pg/Z, [Xbase, Zindices.D, LSL #2] @@ -5117,25 +5031,6 @@ internal Arm64() { } // Load 32-bit data and zero-extend, first-faulting - /// - /// svint64_t svldff1uw_gather_[s64]index_s64(svbool_t pg, const uint32_t *base, svint64_t indices) - /// LDFF1W Zresult.D, Pg/Z, [Xbase, Zindices.D, LSL #2] - /// - public static unsafe Vector GatherVectorUInt32ZeroExtendFirstFaulting(Vector mask, uint* address, Vector indices) { throw new PlatformNotSupportedException(); } - - // - // svint64_t svldff1uw_gather[_u64base]_s64(svbool_t pg, svuint64_t bases) - // LDFF1W Zresult.D, Pg/Z, [Zbases.D, #0] - // - // Removed as per #103297 - // public static Vector GatherVectorUInt32ZeroExtendFirstFaulting(Vector mask, Vector addresses) { throw new PlatformNotSupportedException(); } - - /// - /// svint64_t svldff1uw_gather_[u64]index_s64(svbool_t pg, const uint32_t *base, svuint64_t indices) - /// LDFF1W Zresult.D, Pg/Z, [Xbase, Zindices.D, LSL #2] - /// - public static unsafe Vector GatherVectorUInt32ZeroExtendFirstFaulting(Vector mask, uint* address, Vector indices) { throw new PlatformNotSupportedException(); } - /// /// svint64_t svldff1uw_gather_[s64]index_s64(svbool_t pg, const uint32_t *base, svint64_t indices) /// LDFF1W Zresult.D, Pg/Z, [Xbase, Zindices.D, LSL #2] @@ -5154,25 +5049,6 @@ internal Arm64() { } /// public static unsafe Vector GatherVectorUInt32ZeroExtendFirstFaulting(Vector mask, uint* address, Vector indices) { throw new PlatformNotSupportedException(); } - /// - /// svuint64_t svldff1uw_gather_[s64]index_u64(svbool_t pg, const uint32_t *base, svint64_t indices) - /// LDFF1W Zresult.D, Pg/Z, [Xbase, Zindices.D, LSL #2] - /// - public static unsafe Vector GatherVectorUInt32ZeroExtendFirstFaulting(Vector mask, uint* address, Vector indices) { throw new PlatformNotSupportedException(); } - - // - // svuint64_t svldff1uw_gather[_u64base]_u64(svbool_t pg, svuint64_t bases) - // LDFF1W Zresult.D, Pg/Z, [Zbases.D, #0] - // - // Removed as per #103297 - // public static Vector GatherVectorUInt32ZeroExtendFirstFaulting(Vector mask, Vector addresses) { throw new PlatformNotSupportedException(); } - - /// - /// svuint64_t svldff1uw_gather_[u64]index_u64(svbool_t pg, const uint32_t *base, svuint64_t indices) - /// LDFF1W Zresult.D, Pg/Z, [Xbase, Zindices.D, LSL #2] - /// - public static unsafe Vector GatherVectorUInt32ZeroExtendFirstFaulting(Vector mask, uint* address, Vector indices) { throw new PlatformNotSupportedException(); } - /// /// svuint64_t svldff1uw_gather_[s64]index_u64(svbool_t pg, const uint32_t *base, svint64_t indices) /// LDFF1W Zresult.D, Pg/Z, [Xbase, Zindices.D, LSL #2] diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.cs index 69d4375549fd7d..c6cf60093d09a4 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.cs @@ -4935,18 +4935,6 @@ internal Arm64() { } // Load 32-bit data and zero-extend - /// - /// svint64_t svld1uw_gather_[s64]offset_s64(svbool_t pg, const uint32_t *base, svint64_t offsets) - /// LD1W Zresult.D, Pg/Z, [Xbase, Zoffsets.D] - /// - public static unsafe Vector GatherVectorUInt32WithByteOffsetsZeroExtend(Vector mask, uint* address, Vector offsets) => GatherVectorUInt32WithByteOffsetsZeroExtend(mask, address, offsets); - - /// - /// svint64_t svld1uw_gather_[u64]offset_s64(svbool_t pg, const uint32_t *base, svuint64_t offsets) - /// LD1W Zresult.D, Pg/Z, [Xbase, Zoffsets.D] - /// - public static unsafe Vector GatherVectorUInt32WithByteOffsetsZeroExtend(Vector mask, uint* address, Vector offsets) => GatherVectorUInt32WithByteOffsetsZeroExtend(mask, address, offsets); - /// /// svint64_t svld1uw_gather_[s64]offset_s64(svbool_t pg, const uint32_t *base, svint64_t offsets) /// LD1W Zresult.D, Pg/Z, [Xbase, Zoffsets.D] @@ -4959,18 +4947,6 @@ internal Arm64() { } /// public static unsafe Vector GatherVectorUInt32WithByteOffsetsZeroExtend(Vector mask, uint* address, Vector offsets) => GatherVectorUInt32WithByteOffsetsZeroExtend(mask, address, offsets); - /// - /// svuint64_t svld1uw_gather_[s64]offset_u64(svbool_t pg, const uint32_t *base, svint64_t offsets) - /// LD1W Zresult.D, Pg/Z, [Xbase, Zoffsets.D] - /// - public static unsafe Vector GatherVectorUInt32WithByteOffsetsZeroExtend(Vector mask, uint* address, Vector offsets) => GatherVectorUInt32WithByteOffsetsZeroExtend(mask, address, offsets); - - /// - /// svuint64_t svld1uw_gather_[u64]offset_u64(svbool_t pg, const uint32_t *base, svuint64_t offsets) - /// LD1W Zresult.D, Pg/Z, [Xbase, Zoffsets.D] - /// - public static unsafe Vector GatherVectorUInt32WithByteOffsetsZeroExtend(Vector mask, uint* address, Vector offsets) => GatherVectorUInt32WithByteOffsetsZeroExtend(mask, address, offsets); - /// /// svuint64_t svld1uw_gather_[s64]offset_u64(svbool_t pg, const uint32_t *base, svint64_t offsets) /// LD1W Zresult.D, Pg/Z, [Xbase, Zoffsets.D] @@ -4986,18 +4962,6 @@ internal Arm64() { } // Load 32-bit data and zero-extend, first-faulting - /// - /// svint64_t svldff1uw_gather_[s64]offset_s64(svbool_t pg, const uint32_t *base, svint64_t offsets) - /// LDFF1W Zresult.D, Pg/Z, [Xbase, Zoffsets.D] - /// - public static unsafe Vector GatherVectorUInt32WithByteOffsetsZeroExtendFirstFaulting(Vector mask, uint* address, Vector offsets) => GatherVectorUInt32WithByteOffsetsZeroExtendFirstFaulting(mask, address, offsets); - - /// - /// svint64_t svldff1uw_gather_[u64]offset_s64(svbool_t pg, const uint32_t *base, svuint64_t offsets) - /// LDFF1W Zresult.D, Pg/Z, [Xbase, Zoffsets.D] - /// - public static unsafe Vector GatherVectorUInt32WithByteOffsetsZeroExtendFirstFaulting(Vector mask, uint* address, Vector offsets) => GatherVectorUInt32WithByteOffsetsZeroExtendFirstFaulting(mask, address, offsets); - /// /// svint64_t svldff1uw_gather_[s64]offset_s64(svbool_t pg, const uint32_t *base, svint64_t offsets) /// LDFF1W Zresult.D, Pg/Z, [Xbase, Zoffsets.D] @@ -5010,18 +4974,6 @@ internal Arm64() { } /// public static unsafe Vector GatherVectorUInt32WithByteOffsetsZeroExtendFirstFaulting(Vector mask, uint* address, Vector offsets) => GatherVectorUInt32WithByteOffsetsZeroExtendFirstFaulting(mask, address, offsets); - /// - /// svuint64_t svldff1uw_gather_[s64]offset_u64(svbool_t pg, const uint32_t *base, svint64_t offsets) - /// LDFF1W Zresult.D, Pg/Z, [Xbase, Zoffsets.D] - /// - public static unsafe Vector GatherVectorUInt32WithByteOffsetsZeroExtendFirstFaulting(Vector mask, uint* address, Vector offsets) => GatherVectorUInt32WithByteOffsetsZeroExtendFirstFaulting(mask, address, offsets); - - /// - /// svuint64_t svldff1uw_gather_[u64]offset_u64(svbool_t pg, const uint32_t *base, svuint64_t offsets) - /// LDFF1W Zresult.D, Pg/Z, [Xbase, Zoffsets.D] - /// - public static unsafe Vector GatherVectorUInt32WithByteOffsetsZeroExtendFirstFaulting(Vector mask, uint* address, Vector offsets) => GatherVectorUInt32WithByteOffsetsZeroExtendFirstFaulting(mask, address, offsets); - /// /// svuint64_t svldff1uw_gather_[s64]offset_u64(svbool_t pg, const uint32_t *base, svint64_t offsets) /// LDFF1W Zresult.D, Pg/Z, [Xbase, Zoffsets.D] @@ -5037,25 +4989,6 @@ internal Arm64() { } // Load 32-bit data and zero-extend - /// - /// svint64_t svld1uw_gather_[s64]index_s64(svbool_t pg, const uint32_t *base, svint64_t indices) - /// LD1W Zresult.D, Pg/Z, [Xbase, Zindices.D, LSL #2] - /// - public static unsafe Vector GatherVectorUInt32ZeroExtend(Vector mask, uint* address, Vector indices) => GatherVectorUInt32ZeroExtend(mask, address, indices); - - // - // svint64_t svld1uw_gather[_u64base]_s64(svbool_t pg, svuint64_t bases) - // LD1W Zresult.D, Pg/Z, [Zbases.D, #0] - // - // Removed as per #103297 - // public static Vector GatherVectorUInt32ZeroExtend(Vector mask, Vector addresses) => GatherVectorUInt32ZeroExtend(mask, addresses); - - /// - /// svint64_t svld1uw_gather_[u64]index_s64(svbool_t pg, const uint32_t *base, svuint64_t indices) - /// LD1W Zresult.D, Pg/Z, [Xbase, Zindices.D, LSL #2] - /// - public static unsafe Vector GatherVectorUInt32ZeroExtend(Vector mask, uint* address, Vector indices) => GatherVectorUInt32ZeroExtend(mask, address, indices); - /// /// svint64_t svld1uw_gather_[s64]index_s64(svbool_t pg, const uint32_t *base, svint64_t indices) /// LD1W Zresult.D, Pg/Z, [Xbase, Zindices.D, LSL #2] @@ -5074,25 +5007,6 @@ internal Arm64() { } /// public static unsafe Vector GatherVectorUInt32ZeroExtend(Vector mask, uint* address, Vector indices) => GatherVectorUInt32ZeroExtend(mask, address, indices); - /// - /// svuint64_t svld1uw_gather_[s64]index_u64(svbool_t pg, const uint32_t *base, svint64_t indices) - /// LD1W Zresult.D, Pg/Z, [Xbase, Zindices.D, LSL #2] - /// - public static unsafe Vector GatherVectorUInt32ZeroExtend(Vector mask, uint* address, Vector indices) => GatherVectorUInt32ZeroExtend(mask, address, indices); - - // - // svuint64_t svld1uw_gather[_u64base]_u64(svbool_t pg, svuint64_t bases) - // LD1W Zresult.D, Pg/Z, [Zbases.D, #0] - // - // Removed as per #103297 - // public static Vector GatherVectorUInt32ZeroExtend(Vector mask, Vector addresses) => GatherVectorUInt32ZeroExtend(mask, addresses); - - /// - /// svuint64_t svld1uw_gather_[u64]index_u64(svbool_t pg, const uint32_t *base, svuint64_t indices) - /// LD1W Zresult.D, Pg/Z, [Xbase, Zindices.D, LSL #2] - /// - public static unsafe Vector GatherVectorUInt32ZeroExtend(Vector mask, uint* address, Vector indices) => GatherVectorUInt32ZeroExtend(mask, address, indices); - /// /// svuint64_t svld1uw_gather_[s64]index_u64(svbool_t pg, const uint32_t *base, svint64_t indices) /// LD1W Zresult.D, Pg/Z, [Xbase, Zindices.D, LSL #2] @@ -5114,25 +5028,6 @@ internal Arm64() { } // Load 32-bit data and zero-extend, first-faulting - /// - /// svint64_t svldff1uw_gather_[s64]index_s64(svbool_t pg, const uint32_t *base, svint64_t indices) - /// LDFF1W Zresult.D, Pg/Z, [Xbase, Zindices.D, LSL #2] - /// - public static unsafe Vector GatherVectorUInt32ZeroExtendFirstFaulting(Vector mask, uint* address, Vector indices) => GatherVectorUInt32ZeroExtendFirstFaulting(mask, address, indices); - - // - // svint64_t svldff1uw_gather[_u64base]_s64(svbool_t pg, svuint64_t bases) - // LDFF1W Zresult.D, Pg/Z, [Zbases.D, #0] - // - // Removed as per #103297 - // public static Vector GatherVectorUInt32ZeroExtendFirstFaulting(Vector mask, Vector addresses) => GatherVectorUInt32ZeroExtendFirstFaulting(mask, addresses); - - /// - /// svint64_t svldff1uw_gather_[u64]index_s64(svbool_t pg, const uint32_t *base, svuint64_t indices) - /// LDFF1W Zresult.D, Pg/Z, [Xbase, Zindices.D, LSL #2] - /// - public static unsafe Vector GatherVectorUInt32ZeroExtendFirstFaulting(Vector mask, uint* address, Vector indices) => GatherVectorUInt32ZeroExtendFirstFaulting(mask, address, indices); - /// /// svint64_t svldff1uw_gather_[s64]index_s64(svbool_t pg, const uint32_t *base, svint64_t indices) /// LDFF1W Zresult.D, Pg/Z, [Xbase, Zindices.D, LSL #2] @@ -5151,25 +5046,6 @@ internal Arm64() { } /// public static unsafe Vector GatherVectorUInt32ZeroExtendFirstFaulting(Vector mask, uint* address, Vector indices) => GatherVectorUInt32ZeroExtendFirstFaulting(mask, address, indices); - /// - /// svuint64_t svldff1uw_gather_[s64]index_u64(svbool_t pg, const uint32_t *base, svint64_t indices) - /// LDFF1W Zresult.D, Pg/Z, [Xbase, Zindices.D, LSL #2] - /// - public static unsafe Vector GatherVectorUInt32ZeroExtendFirstFaulting(Vector mask, uint* address, Vector indices) => GatherVectorUInt32ZeroExtendFirstFaulting(mask, address, indices); - - // - // svuint64_t svldff1uw_gather[_u64base]_u64(svbool_t pg, svuint64_t bases) - // LDFF1W Zresult.D, Pg/Z, [Zbases.D, #0] - // - // Removed as per #103297 - // public static Vector GatherVectorUInt32ZeroExtendFirstFaulting(Vector mask, Vector addresses) => GatherVectorUInt32ZeroExtendFirstFaulting(mask, addresses); - - /// - /// svuint64_t svldff1uw_gather_[u64]index_u64(svbool_t pg, const uint32_t *base, svuint64_t indices) - /// LDFF1W Zresult.D, Pg/Z, [Xbase, Zindices.D, LSL #2] - /// - public static unsafe Vector GatherVectorUInt32ZeroExtendFirstFaulting(Vector mask, uint* address, Vector indices) => GatherVectorUInt32ZeroExtendFirstFaulting(mask, address, indices); - /// /// svuint64_t svldff1uw_gather_[s64]index_u64(svbool_t pg, const uint32_t *base, svint64_t indices) /// LDFF1W Zresult.D, Pg/Z, [Xbase, Zindices.D, LSL #2] diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve2.PlatformNotSupported.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve2.PlatformNotSupported.cs index add56b177a1390..1eb32eba2be1ca 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve2.PlatformNotSupported.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve2.PlatformNotSupported.cs @@ -1479,6 +1479,584 @@ internal Arm64() { } public static Vector FusedAddRoundedHalving(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + // Load 8-bit data and zero-extend, non-temporal + + // + // svint32_t svldnt1ub_gather[_u32base]_s32(svbool_t pg, svuint32_t bases) + // LDNT1B Zresult.S, Pg/Z, [Zbases.S, XZR] + // + // Removed as per #103297 + // public static unsafe Vector GatherVectorByteZeroExtendNonTemporal(Vector mask, Vector addresses) { throw new PlatformNotSupportedException(); } + + /// + /// svint32_t svldnt1ub_gather_[u32]offset_s32(svbool_t pg, const uint8_t *base, svuint32_t offsets) + /// LDNT1B Zresult.S, Pg/Z, [Zoffsets.S, Xbase] + /// + public static unsafe Vector GatherVectorByteZeroExtendNonTemporal(Vector mask, byte* address, Vector offsets) { throw new PlatformNotSupportedException(); } + + /// + /// svint64_t svldnt1ub_gather[_u64base]_s64(svbool_t pg, svuint64_t bases) + /// LDNT1B Zresult.D, Pg/Z, [Zbases.D, XZR] + /// + public static unsafe Vector GatherVectorByteZeroExtendNonTemporal(Vector mask, Vector addresses) { throw new PlatformNotSupportedException(); } + + /// + /// svint64_t svldnt1ub_gather_[s64]offset_s64(svbool_t pg, const uint8_t *base, svint64_t offsets) + /// LDNT1B Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorByteZeroExtendNonTemporal(Vector mask, byte* address, Vector offsets) { throw new PlatformNotSupportedException(); } + + /// + /// svint64_t svldnt1ub_gather_[u64]offset_s64(svbool_t pg, const uint8_t *base, svuint64_t offsets) + /// LDNT1B Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorByteZeroExtendNonTemporal(Vector mask, byte* address, Vector offsets) { throw new PlatformNotSupportedException(); } + + // + // svuint32_t svldnt1ub_gather[_u32base]_u32(svbool_t pg, svuint32_t bases) + // LDNT1B Zresult.S, Pg/Z, [Zbases.S, XZR] + // + // Removed as per #103297 + // public static unsafe Vector GatherVectorByteZeroExtendNonTemporal(Vector mask, Vector addresses) { throw new PlatformNotSupportedException(); } + + /// + /// svuint32_t svldnt1ub_gather_[u32]offset_u32(svbool_t pg, const uint8_t *base, svuint32_t offsets) + /// LDNT1B Zresult.S, Pg/Z, [Zoffsets.S, Xbase] + /// + public static unsafe Vector GatherVectorByteZeroExtendNonTemporal(Vector mask, byte* address, Vector offsets) { throw new PlatformNotSupportedException(); } + + /// + /// svuint64_t svldnt1ub_gather[_u64base]_u64(svbool_t pg, svuint64_t bases) + /// LDNT1B Zresult.D, Pg/Z, [Zbases.D, XZR] + /// + public static unsafe Vector GatherVectorByteZeroExtendNonTemporal(Vector mask, Vector addresses) { throw new PlatformNotSupportedException(); } + + /// + /// svuint64_t svldnt1ub_gather_[s64]offset_u64(svbool_t pg, const uint8_t *base, svint64_t offsets) + /// LDNT1B Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorByteZeroExtendNonTemporal(Vector mask, byte* address, Vector offsets) { throw new PlatformNotSupportedException(); } + + /// + /// svuint64_t svldnt1ub_gather_[u64]offset_u64(svbool_t pg, const uint8_t *base, svuint64_t offsets) + /// LDNT1B Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorByteZeroExtendNonTemporal(Vector mask, byte* address, Vector offsets) { throw new PlatformNotSupportedException(); } + + + // Load 16-bit data and sign-extend, non-temporal + + // + // svint32_t svldnt1sh_gather[_u32base]_s32(svbool_t pg, svuint32_t bases) + // LDNT1SH Zresult.S, Pg/Z, [Zbases.S, XZR] + // + // Removed as per #103297 + // public static unsafe Vector GatherVectorInt16SignExtendNonTemporal(Vector mask, Vector addresses) { throw new PlatformNotSupportedException(); } + + /// + /// svint64_t svldnt1sh_gather[_u64base]_s64(svbool_t pg, svuint64_t bases) + /// LDNT1SH Zresult.D, Pg/Z, [Zbases.D, XZR] + /// + public static unsafe Vector GatherVectorInt16SignExtendNonTemporal(Vector mask, Vector addresses) { throw new PlatformNotSupportedException(); } + + /// + /// svint64_t svldnt1sh_gather_[s64]index_s64(svbool_t pg, const int16_t *base, svint64_t indices) + /// LDNT1SH Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorInt16SignExtendNonTemporal(Vector mask, short* address, Vector indices) { throw new PlatformNotSupportedException(); } + + /// + /// svint64_t svldnt1sh_gather_[u64]index_s64(svbool_t pg, const int16_t *base, svuint64_t indices) + /// LDNT1SH Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorInt16SignExtendNonTemporal(Vector mask, short* address, Vector indices) { throw new PlatformNotSupportedException(); } + + // + // svuint32_t svldnt1sh_gather[_u32base]_u32(svbool_t pg, svuint32_t bases) + // LDNT1SH Zresult.S, Pg/Z, [Zbases.S, XZR] + // + // Removed as per #103297 + // public static unsafe Vector GatherVectorInt16SignExtendNonTemporal(Vector mask, Vector addresses) { throw new PlatformNotSupportedException(); } + + /// + /// svuint64_t svldnt1sh_gather[_u64base]_u64(svbool_t pg, svuint64_t bases) + /// LDNT1SH Zresult.D, Pg/Z, [Zbases.D, XZR] + /// + public static unsafe Vector GatherVectorInt16SignExtendNonTemporal(Vector mask, Vector addresses) { throw new PlatformNotSupportedException(); } + + /// + /// svuint64_t svldnt1sh_gather_[s64]index_u64(svbool_t pg, const int16_t *base, svint64_t indices) + /// LDNT1SH Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorInt16SignExtendNonTemporal(Vector mask, short* address, Vector indices) { throw new PlatformNotSupportedException(); } + + /// + /// svuint64_t svldnt1sh_gather_[u64]index_u64(svbool_t pg, const int16_t *base, svuint64_t indices) + /// LDNT1SH Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorInt16SignExtendNonTemporal(Vector mask, short* address, Vector indices) { throw new PlatformNotSupportedException(); } + + + // Load 16-bit data and sign-extend, non-temporal + + /// + /// svint32_t svldnt1sh_gather_[u32]offset_s32(svbool_t pg, const int16_t *base, svuint32_t offsets) + /// LDNT1SH Zresult.S, Pg/Z, [Zoffsets.S, Xbase] + /// + public static unsafe Vector GatherVectorInt16WithByteOffsetsSignExtendNonTemporal(Vector mask, short* address, Vector offsets) { throw new PlatformNotSupportedException(); } + + /// + /// svint64_t svldnt1sh_gather_[s64]offset_s64(svbool_t pg, const int16_t *base, svint64_t offsets) + /// LDNT1SH Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorInt16WithByteOffsetsSignExtendNonTemporal(Vector mask, short* address, Vector offsets) { throw new PlatformNotSupportedException(); } + + /// + /// svint64_t svldnt1sh_gather_[u64]offset_s64(svbool_t pg, const int16_t *base, svuint64_t offsets) + /// LDNT1SH Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorInt16WithByteOffsetsSignExtendNonTemporal(Vector mask, short* address, Vector offsets) { throw new PlatformNotSupportedException(); } + + /// + /// svuint32_t svldnt1sh_gather_[u32]offset_u32(svbool_t pg, const int16_t *base, svuint32_t offsets) + /// LDNT1SH Zresult.S, Pg/Z, [Zoffsets.S, Xbase] + /// + public static unsafe Vector GatherVectorInt16WithByteOffsetsSignExtendNonTemporal(Vector mask, short* address, Vector offsets) { throw new PlatformNotSupportedException(); } + + /// + /// svuint64_t svldnt1sh_gather_[s64]offset_u64(svbool_t pg, const int16_t *base, svint64_t offsets) + /// LDNT1SH Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorInt16WithByteOffsetsSignExtendNonTemporal(Vector mask, short* address, Vector offsets) { throw new PlatformNotSupportedException(); } + + /// + /// svuint64_t svldnt1sh_gather_[u64]offset_u64(svbool_t pg, const int16_t *base, svuint64_t offsets) + /// LDNT1SH Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorInt16WithByteOffsetsSignExtendNonTemporal(Vector mask, short* address, Vector offsets) { throw new PlatformNotSupportedException(); } + + + // Load 32-bit data and sign-extend, non-temporal + + /// + /// svint64_t svldnt1sw_gather[_u64base]_s64(svbool_t pg, svuint64_t bases) + /// LDNT1SW Zresult.D, Pg/Z, [Zbases.D, XZR] + /// + public static unsafe Vector GatherVectorInt32SignExtendNonTemporal(Vector mask, Vector addresses) { throw new PlatformNotSupportedException(); } + + /// + /// svint64_t svldnt1sw_gather_[s64]index_s64(svbool_t pg, const int32_t *base, svint64_t indices) + /// LDNT1SW Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorInt32SignExtendNonTemporal(Vector mask, int* address, Vector indices) { throw new PlatformNotSupportedException(); } + + /// + /// svint64_t svldnt1sw_gather_[u64]index_s64(svbool_t pg, const int32_t *base, svuint64_t indices) + /// LDNT1SW Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorInt32SignExtendNonTemporal(Vector mask, int* address, Vector indices) { throw new PlatformNotSupportedException(); } + + /// + /// svuint64_t svldnt1sw_gather[_u64base]_u64(svbool_t pg, svuint64_t bases) + /// LDNT1SW Zresult.D, Pg/Z, [Zbases.D, XZR] + /// + public static unsafe Vector GatherVectorInt32SignExtendNonTemporal(Vector mask, Vector addresses) { throw new PlatformNotSupportedException(); } + + /// + /// svuint64_t svldnt1sw_gather_[s64]index_u64(svbool_t pg, const int32_t *base, svint64_t indices) + /// LDNT1SW Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorInt32SignExtendNonTemporal(Vector mask, int* address, Vector indices) { throw new PlatformNotSupportedException(); } + + /// + /// svuint64_t svldnt1sw_gather_[u64]index_u64(svbool_t pg, const int32_t *base, svuint64_t indices) + /// LDNT1SW Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorInt32SignExtendNonTemporal(Vector mask, int* address, Vector indices) { throw new PlatformNotSupportedException(); } + + + // Load 32-bit data and sign-extend, non-temporal + + /// + /// svint64_t svldnt1sw_gather_[s64]offset_s64(svbool_t pg, const int32_t *base, svint64_t offsets) + /// LDNT1SW Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorInt32WithByteOffsetsSignExtendNonTemporal(Vector mask, int* address, Vector offsets) { throw new PlatformNotSupportedException(); } + + /// + /// svint64_t svldnt1sw_gather_[u64]offset_s64(svbool_t pg, const int32_t *base, svuint64_t offsets) + /// LDNT1SW Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorInt32WithByteOffsetsSignExtendNonTemporal(Vector mask, int* address, Vector offsets) { throw new PlatformNotSupportedException(); } + + /// + /// svuint64_t svldnt1sw_gather_[s64]offset_u64(svbool_t pg, const int32_t *base, svint64_t offsets) + /// LDNT1SW Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorInt32WithByteOffsetsSignExtendNonTemporal(Vector mask, int* address, Vector offsets) { throw new PlatformNotSupportedException(); } + + /// + /// svuint64_t svldnt1sw_gather_[u64]offset_u64(svbool_t pg, const int32_t *base, svuint64_t offsets) + /// LDNT1SW Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorInt32WithByteOffsetsSignExtendNonTemporal(Vector mask, int* address, Vector offsets) { throw new PlatformNotSupportedException(); } + + + // Unextended load, non-temporal + + /// + /// svfloat64_t svldnt1_gather[_u64base]_f64(svbool_t pg, svuint64_t bases) + /// LDNT1D Zresult.D, Pg/Z, [Zbases.D, XZR] + /// + public static unsafe Vector GatherVectorNonTemporal(Vector mask, Vector addresses) { throw new PlatformNotSupportedException(); } + + /// + /// svfloat64_t svldnt1_gather_[s64]index[_f64](svbool_t pg, const float64_t *base, svint64_t indices) + /// LDNT1D Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorNonTemporal(Vector mask, double* address, Vector indices) { throw new PlatformNotSupportedException(); } + + /// + /// svfloat64_t svldnt1_gather_[u64]index[_f64](svbool_t pg, const float64_t *base, svuint64_t indices) + /// LDNT1D Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorNonTemporal(Vector mask, double* address, Vector indices) { throw new PlatformNotSupportedException(); } + + // + // svint32_t svldnt1_gather[_u32base]_s32(svbool_t pg, svuint32_t bases) + // LDNT1W Zresult.S, Pg/Z, [Zbases.S, XZR] + // + // Removed as per #103297 + // public static unsafe Vector GatherVectorNonTemporal(Vector mask, Vector addresses) { throw new PlatformNotSupportedException(); } + + /// + /// svint64_t svldnt1_gather[_u64base]_s64(svbool_t pg, svuint64_t bases) + /// LDNT1D Zresult.D, Pg/Z, [Zbases.D, XZR] + /// + public static unsafe Vector GatherVectorNonTemporal(Vector mask, Vector addresses) { throw new PlatformNotSupportedException(); } + + /// + /// svint64_t svldnt1_gather_[s64]index[_s64](svbool_t pg, const int64_t *base, svint64_t indices) + /// LDNT1D Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorNonTemporal(Vector mask, long* address, Vector indices) { throw new PlatformNotSupportedException(); } + + /// + /// svint64_t svldnt1_gather_[u64]index[_s64](svbool_t pg, const int64_t *base, svuint64_t indices) + /// LDNT1D Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorNonTemporal(Vector mask, long* address, Vector indices) { throw new PlatformNotSupportedException(); } + + // + // svfloat32_t svldnt1_gather[_u32base]_f32(svbool_t pg, svuint32_t bases) + // LDNT1W Zresult.S, Pg/Z, [Zbases.S, XZR] + // + // Removed as per #103297 + // public static unsafe Vector GatherVectorNonTemporal(Vector mask, Vector addresses) { throw new PlatformNotSupportedException(); } + + // + // svuint32_t svldnt1_gather[_u32base]_u32(svbool_t pg, svuint32_t bases) + // LDNT1W Zresult.S, Pg/Z, [Zbases.S, XZR] + // + // Removed as per #103297 + // public static unsafe Vector GatherVectorNonTemporal(Vector mask, Vector addresses) { throw new PlatformNotSupportedException(); } + + /// + /// svuint64_t svldnt1_gather[_u64base]_u64(svbool_t pg, svuint64_t bases) + /// LDNT1D Zresult.D, Pg/Z, [Zbases.D, XZR] + /// + public static unsafe Vector GatherVectorNonTemporal(Vector mask, Vector addresses) { throw new PlatformNotSupportedException(); } + + /// + /// svuint64_t svldnt1_gather_[s64]index[_u64](svbool_t pg, const uint64_t *base, svint64_t indices) + /// LDNT1D Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorNonTemporal(Vector mask, ulong* address, Vector indices) { throw new PlatformNotSupportedException(); } + + /// + /// svuint64_t svldnt1_gather_[u64]index[_u64](svbool_t pg, const uint64_t *base, svuint64_t indices) + /// LDNT1D Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorNonTemporal(Vector mask, ulong* address, Vector indices) { throw new PlatformNotSupportedException(); } + + /// + /// svfloat64_t svldnt1_gather_[s64]offset[_f64](svbool_t pg, const float64_t *base, svint64_t offsets) + /// LDNT1D Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorWithByteOffsetsNonTemporal(Vector mask, double* address, Vector offsets) { throw new PlatformNotSupportedException(); } + + /// + /// svfloat64_t svldnt1_gather_[u64]offset[_f64](svbool_t pg, const float64_t *base, svuint64_t offsets) + /// LDNT1D Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorWithByteOffsetsNonTemporal(Vector mask, double* address, Vector offsets) { throw new PlatformNotSupportedException(); } + + /// + /// svint32_t svldnt1_gather_[u32]offset[_s32](svbool_t pg, const int32_t *base, svuint32_t offsets) + /// LDNT1W Zresult.S, Pg/Z, [Zoffsets.S, Xbase] + /// + public static unsafe Vector GatherVectorWithByteOffsetsNonTemporal(Vector mask, int* address, Vector offsets) { throw new PlatformNotSupportedException(); } + + /// + /// svint64_t svldnt1_gather_[s64]offset[_s64](svbool_t pg, const int64_t *base, svint64_t offsets) + /// LDNT1D Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorWithByteOffsetsNonTemporal(Vector mask, long* address, Vector offsets) { throw new PlatformNotSupportedException(); } + + /// + /// svint64_t svldnt1_gather_[u64]offset[_s64](svbool_t pg, const int64_t *base, svuint64_t offsets) + /// LDNT1D Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorWithByteOffsetsNonTemporal(Vector mask, long* address, Vector offsets) { throw new PlatformNotSupportedException(); } + + /// + /// svfloat32_t svldnt1_gather_[u32]offset[_f32](svbool_t pg, const float32_t *base, svuint32_t offsets) + /// LDNT1W Zresult.S, Pg/Z, [Zoffsets.S, Xbase] + /// + public static unsafe Vector GatherVectorWithByteOffsetsNonTemporal(Vector mask, float* address, Vector offsets) { throw new PlatformNotSupportedException(); } + + /// + /// svuint32_t svldnt1_gather_[u32]offset[_u32](svbool_t pg, const uint32_t *base, svuint32_t offsets) + /// LDNT1W Zresult.S, Pg/Z, [Zoffsets.S, Xbase] + /// + public static unsafe Vector GatherVectorWithByteOffsetsNonTemporal(Vector mask, uint* address, Vector offsets) { throw new PlatformNotSupportedException(); } + + /// + /// svuint64_t svldnt1_gather_[s64]offset[_u64](svbool_t pg, const uint64_t *base, svint64_t offsets) + /// LDNT1D Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorWithByteOffsetsNonTemporal(Vector mask, ulong* address, Vector offsets) { throw new PlatformNotSupportedException(); } + + /// + /// svuint64_t svldnt1_gather_[u64]offset[_u64](svbool_t pg, const uint64_t *base, svuint64_t offsets) + /// LDNT1D Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorWithByteOffsetsNonTemporal(Vector mask, ulong* address, Vector offsets) { throw new PlatformNotSupportedException(); } + + + // Load 8-bit data and sign-extend, non-temporal + + // + // svint32_t svldnt1sb_gather[_u32base]_s32(svbool_t pg, svuint32_t bases) + // LDNT1SB Zresult.S, Pg/Z, [Zbases.S, XZR] + // + // Removed as per #103297 + // public static unsafe Vector GatherVectorSByteSignExtendNonTemporal(Vector mask, Vector addresses) { throw new PlatformNotSupportedException(); } + + /// + /// svint32_t svldnt1sb_gather_[u32]offset_s32(svbool_t pg, const int8_t *base, svuint32_t offsets) + /// LDNT1SB Zresult.S, Pg/Z, [Zoffsets.S, Xbase] + /// + public static unsafe Vector GatherVectorSByteSignExtendNonTemporal(Vector mask, sbyte* address, Vector offsets) { throw new PlatformNotSupportedException(); } + + /// + /// svint64_t svldnt1sb_gather[_u64base]_s64(svbool_t pg, svuint64_t bases) + /// LDNT1SB Zresult.D, Pg/Z, [Zbases.D, XZR] + /// + public static unsafe Vector GatherVectorSByteSignExtendNonTemporal(Vector mask, Vector addresses) { throw new PlatformNotSupportedException(); } + + /// + /// svint64_t svldnt1sb_gather_[s64]offset_s64(svbool_t pg, const int8_t *base, svint64_t offsets) + /// LDNT1SB Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorSByteSignExtendNonTemporal(Vector mask, sbyte* address, Vector offsets) { throw new PlatformNotSupportedException(); } + + /// + /// svint64_t svldnt1sb_gather_[u64]offset_s64(svbool_t pg, const int8_t *base, svuint64_t offsets) + /// LDNT1SB Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorSByteSignExtendNonTemporal(Vector mask, sbyte* address, Vector offsets) { throw new PlatformNotSupportedException(); } + + // + // svuint32_t svldnt1sb_gather[_u32base]_u32(svbool_t pg, svuint32_t bases) + // LDNT1SB Zresult.S, Pg/Z, [Zbases.S, XZR] + // + // Removed as per #103297 + // public static unsafe Vector GatherVectorSByteSignExtendNonTemporal(Vector mask, Vector addresses) { throw new PlatformNotSupportedException(); } + + /// + /// svuint32_t svldnt1sb_gather_[u32]offset_u32(svbool_t pg, const int8_t *base, svuint32_t offsets) + /// LDNT1SB Zresult.S, Pg/Z, [Zoffsets.S, Xbase] + /// + public static unsafe Vector GatherVectorSByteSignExtendNonTemporal(Vector mask, sbyte* address, Vector offsets) { throw new PlatformNotSupportedException(); } + + /// + /// svuint64_t svldnt1sb_gather[_u64base]_u64(svbool_t pg, svuint64_t bases) + /// LDNT1SB Zresult.D, Pg/Z, [Zbases.D, XZR] + /// + public static unsafe Vector GatherVectorSByteSignExtendNonTemporal(Vector mask, Vector addresses) { throw new PlatformNotSupportedException(); } + + /// + /// svuint64_t svldnt1sb_gather_[s64]offset_u64(svbool_t pg, const int8_t *base, svint64_t offsets) + /// LDNT1SB Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorSByteSignExtendNonTemporal(Vector mask, sbyte* address, Vector offsets) { throw new PlatformNotSupportedException(); } + + /// + /// svuint64_t svldnt1sb_gather_[u64]offset_u64(svbool_t pg, const int8_t *base, svuint64_t offsets) + /// LDNT1SB Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorSByteSignExtendNonTemporal(Vector mask, sbyte* address, Vector offsets) { throw new PlatformNotSupportedException(); } + + + // Load 16-bit data and zero-extend, non-temporal + + /// + /// svint32_t svldnt1uh_gather_[u32]offset_s32(svbool_t pg, const uint16_t *base, svuint32_t offsets) + /// LDNT1H Zresult.S, Pg/Z, [Zoffsets.S, Xbase] + /// + public static unsafe Vector GatherVectorUInt16WithByteOffsetsZeroExtendNonTemporal(Vector mask, ushort* address, Vector offsets) { throw new PlatformNotSupportedException(); } + + /// + /// svint64_t svldnt1uh_gather_[s64]offset_s64(svbool_t pg, const uint16_t *base, svint64_t offsets) + /// LDNT1H Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorUInt16WithByteOffsetsZeroExtendNonTemporal(Vector mask, ushort* address, Vector offsets) { throw new PlatformNotSupportedException(); } + + /// + /// svint64_t svldnt1uh_gather_[u64]offset_s64(svbool_t pg, const uint16_t *base, svuint64_t offsets) + /// LDNT1H Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorUInt16WithByteOffsetsZeroExtendNonTemporal(Vector mask, ushort* address, Vector offsets) { throw new PlatformNotSupportedException(); } + + /// + /// svuint32_t svldnt1uh_gather_[u32]offset_u32(svbool_t pg, const uint16_t *base, svuint32_t offsets) + /// LDNT1H Zresult.S, Pg/Z, [Zoffsets.S, Xbase] + /// + public static unsafe Vector GatherVectorUInt16WithByteOffsetsZeroExtendNonTemporal(Vector mask, ushort* address, Vector offsets) { throw new PlatformNotSupportedException(); } + + /// + /// svuint64_t svldnt1uh_gather_[s64]offset_u64(svbool_t pg, const uint16_t *base, svint64_t offsets) + /// LDNT1H Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorUInt16WithByteOffsetsZeroExtendNonTemporal(Vector mask, ushort* address, Vector offsets) { throw new PlatformNotSupportedException(); } + + /// + /// svuint64_t svldnt1uh_gather_[u64]offset_u64(svbool_t pg, const uint16_t *base, svuint64_t offsets) + /// LDNT1H Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorUInt16WithByteOffsetsZeroExtendNonTemporal(Vector mask, ushort* address, Vector offsets) { throw new PlatformNotSupportedException(); } + + + // Load 16-bit data and zero-extend, non-temporal + + // + // svint32_t svldnt1uh_gather[_u32base]_s32(svbool_t pg, svuint32_t bases) + // LDNT1H Zresult.S, Pg/Z, [Zbases.S, XZR] + // + // Removed as per #103297 + // public static unsafe Vector GatherVectorUInt16ZeroExtendNonTemporal(Vector mask, Vector addresses) { throw new PlatformNotSupportedException(); } + + /// + /// svint64_t svldnt1uh_gather[_u64base]_s64(svbool_t pg, svuint64_t bases) + /// LDNT1H Zresult.D, Pg/Z, [Zbases.D, XZR] + /// + public static unsafe Vector GatherVectorUInt16ZeroExtendNonTemporal(Vector mask, Vector addresses) { throw new PlatformNotSupportedException(); } + + /// + /// svint64_t svldnt1uh_gather_[s64]index_s64(svbool_t pg, const uint16_t *base, svint64_t indices) + /// LDNT1H Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorUInt16ZeroExtendNonTemporal(Vector mask, ushort* address, Vector indices) { throw new PlatformNotSupportedException(); } + + /// + /// svint64_t svldnt1uh_gather_[u64]index_s64(svbool_t pg, const uint16_t *base, svuint64_t indices) + /// LDNT1H Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorUInt16ZeroExtendNonTemporal(Vector mask, ushort* address, Vector indices) { throw new PlatformNotSupportedException(); } + + // + // svuint32_t svldnt1uh_gather[_u32base]_u32(svbool_t pg, svuint32_t bases) + // LDNT1H Zresult.S, Pg/Z, [Zbases.S, XZR] + // + // Removed as per #103297 + // public static unsafe Vector GatherVectorUInt16ZeroExtendNonTemporal(Vector mask, Vector addresses) { throw new PlatformNotSupportedException(); } + + /// + /// svuint64_t svldnt1uh_gather[_u64base]_u64(svbool_t pg, svuint64_t bases) + /// LDNT1H Zresult.D, Pg/Z, [Zbases.D, XZR] + /// + public static unsafe Vector GatherVectorUInt16ZeroExtendNonTemporal(Vector mask, Vector addresses) { throw new PlatformNotSupportedException(); } + + /// + /// svuint64_t svldnt1uh_gather_[s64]index_u64(svbool_t pg, const uint16_t *base, svint64_t indices) + /// LDNT1H Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorUInt16ZeroExtendNonTemporal(Vector mask, ushort* address, Vector indices) { throw new PlatformNotSupportedException(); } + + /// + /// svuint64_t svldnt1uh_gather_[u64]index_u64(svbool_t pg, const uint16_t *base, svuint64_t indices) + /// LDNT1H Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorUInt16ZeroExtendNonTemporal(Vector mask, ushort* address, Vector indices) { throw new PlatformNotSupportedException(); } + + + // Load 32-bit data and zero-extend, non-temporal + + /// + /// svint64_t svldnt1uw_gather_[s64]offset_s64(svbool_t pg, const uint32_t *base, svint64_t offsets) + /// LDNT1W Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorUInt32WithByteOffsetsZeroExtendNonTemporal(Vector mask, uint* address, Vector offsets) { throw new PlatformNotSupportedException(); } + + /// + /// svint64_t svldnt1uw_gather_[u64]offset_s64(svbool_t pg, const uint32_t *base, svuint64_t offsets) + /// LDNT1W Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorUInt32WithByteOffsetsZeroExtendNonTemporal(Vector mask, uint* address, Vector offsets) { throw new PlatformNotSupportedException(); } + + /// + /// svuint64_t svldnt1uw_gather_[s64]offset_u64(svbool_t pg, const uint32_t *base, svint64_t offsets) + /// LDNT1W Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorUInt32WithByteOffsetsZeroExtendNonTemporal(Vector mask, uint* address, Vector offsets) { throw new PlatformNotSupportedException(); } + + /// + /// svuint64_t svldnt1uw_gather_[u64]offset_u64(svbool_t pg, const uint32_t *base, svuint64_t offsets) + /// LDNT1W Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorUInt32WithByteOffsetsZeroExtendNonTemporal(Vector mask, uint* address, Vector offsets) { throw new PlatformNotSupportedException(); } + + + // Load 32-bit data and zero-extend, non-temporal + + /// + /// svint64_t svldnt1uw_gather[_u64base]_s64(svbool_t pg, svuint64_t bases) + /// LDNT1W Zresult.D, Pg/Z, [Zbases.D, XZR] + /// + public static unsafe Vector GatherVectorUInt32ZeroExtendNonTemporal(Vector mask, Vector addresses) { throw new PlatformNotSupportedException(); } + + /// + /// svint64_t svldnt1uw_gather_[s64]index_s64(svbool_t pg, const uint32_t *base, svint64_t indices) + /// LDNT1W Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorUInt32ZeroExtendNonTemporal(Vector mask, uint* address, Vector indices) { throw new PlatformNotSupportedException(); } + + /// + /// svint64_t svldnt1uw_gather_[u64]index_s64(svbool_t pg, const uint32_t *base, svuint64_t indices) + /// LDNT1W Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorUInt32ZeroExtendNonTemporal(Vector mask, uint* address, Vector indices) { throw new PlatformNotSupportedException(); } + + /// + /// svuint64_t svldnt1uw_gather[_u64base]_u64(svbool_t pg, svuint64_t bases) + /// LDNT1W Zresult.D, Pg/Z, [Zbases.D, XZR] + /// + public static unsafe Vector GatherVectorUInt32ZeroExtendNonTemporal(Vector mask, Vector addresses) { throw new PlatformNotSupportedException(); } + + /// + /// svuint64_t svldnt1uw_gather_[s64]index_u64(svbool_t pg, const uint32_t *base, svint64_t indices) + /// LDNT1W Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorUInt32ZeroExtendNonTemporal(Vector mask, uint* address, Vector indices) { throw new PlatformNotSupportedException(); } + + /// + /// svuint64_t svldnt1uw_gather_[u64]index_u64(svbool_t pg, const uint32_t *base, svuint64_t indices) + /// LDNT1W Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorUInt32ZeroExtendNonTemporal(Vector mask, uint* address, Vector indices) { throw new PlatformNotSupportedException(); } + + /// Interleaving Xor /// diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve2.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve2.cs index 35a2d76a1d322d..a3860a8bb0ecbd 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve2.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve2.cs @@ -1479,6 +1479,584 @@ internal Arm64() { } public static Vector FusedAddRoundedHalving(Vector left, Vector right) => FusedAddRoundedHalving(left, right); + // Load 8-bit data and zero-extend, non-temporal + + // + // svint32_t svldnt1ub_gather[_u32base]_s32(svbool_t pg, svuint32_t bases) + // LDNT1B Zresult.S, Pg/Z, [Zbases.S, XZR] + // + // Removed as per #103297 + // public static unsafe Vector GatherVectorByteZeroExtendNonTemporal(Vector mask, Vector addresses) => GatherVectorByteZeroExtendNonTemporal(mask, addresses); + + /// + /// svint32_t svldnt1ub_gather_[u32]offset_s32(svbool_t pg, const uint8_t *base, svuint32_t offsets) + /// LDNT1B Zresult.S, Pg/Z, [Zoffsets.S, Xbase] + /// + public static unsafe Vector GatherVectorByteZeroExtendNonTemporal(Vector mask, byte* address, Vector offsets) => GatherVectorByteZeroExtendNonTemporal(mask, address, offsets); + + /// + /// svint64_t svldnt1ub_gather[_u64base]_s64(svbool_t pg, svuint64_t bases) + /// LDNT1B Zresult.D, Pg/Z, [Zbases.D, XZR] + /// + public static unsafe Vector GatherVectorByteZeroExtendNonTemporal(Vector mask, Vector addresses) => GatherVectorByteZeroExtendNonTemporal(mask, addresses); + + /// + /// svint64_t svldnt1ub_gather_[s64]offset_s64(svbool_t pg, const uint8_t *base, svint64_t offsets) + /// LDNT1B Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorByteZeroExtendNonTemporal(Vector mask, byte* address, Vector offsets) => GatherVectorByteZeroExtendNonTemporal(mask, address, offsets); + + /// + /// svint64_t svldnt1ub_gather_[u64]offset_s64(svbool_t pg, const uint8_t *base, svuint64_t offsets) + /// LDNT1B Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorByteZeroExtendNonTemporal(Vector mask, byte* address, Vector offsets) => GatherVectorByteZeroExtendNonTemporal(mask, address, offsets); + + // + // svuint32_t svldnt1ub_gather[_u32base]_u32(svbool_t pg, svuint32_t bases) + // LDNT1B Zresult.S, Pg/Z, [Zbases.S, XZR] + // + // Removed as per #103297 + // public static unsafe Vector GatherVectorByteZeroExtendNonTemporal(Vector mask, Vector addresses) => GatherVectorByteZeroExtendNonTemporal(mask, addresses); + + /// + /// svuint32_t svldnt1ub_gather_[u32]offset_u32(svbool_t pg, const uint8_t *base, svuint32_t offsets) + /// LDNT1B Zresult.S, Pg/Z, [Zoffsets.S, Xbase] + /// + public static unsafe Vector GatherVectorByteZeroExtendNonTemporal(Vector mask, byte* address, Vector offsets) => GatherVectorByteZeroExtendNonTemporal(mask, address, offsets); + + /// + /// svuint64_t svldnt1ub_gather[_u64base]_u64(svbool_t pg, svuint64_t bases) + /// LDNT1B Zresult.D, Pg/Z, [Zbases.D, XZR] + /// + public static unsafe Vector GatherVectorByteZeroExtendNonTemporal(Vector mask, Vector addresses) => GatherVectorByteZeroExtendNonTemporal(mask, addresses); + + /// + /// svuint64_t svldnt1ub_gather_[s64]offset_u64(svbool_t pg, const uint8_t *base, svint64_t offsets) + /// LDNT1B Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorByteZeroExtendNonTemporal(Vector mask, byte* address, Vector offsets) => GatherVectorByteZeroExtendNonTemporal(mask, address, offsets); + + /// + /// svuint64_t svldnt1ub_gather_[u64]offset_u64(svbool_t pg, const uint8_t *base, svuint64_t offsets) + /// LDNT1B Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorByteZeroExtendNonTemporal(Vector mask, byte* address, Vector offsets) => GatherVectorByteZeroExtendNonTemporal(mask, address, offsets); + + + // Load 16-bit data and sign-extend, non-temporal + + // + // svint32_t svldnt1sh_gather[_u32base]_s32(svbool_t pg, svuint32_t bases) + // LDNT1SH Zresult.S, Pg/Z, [Zbases.S, XZR] + // + // Removed as per #103297 + // public static unsafe Vector GatherVectorInt16SignExtendNonTemporal(Vector mask, Vector addresses) => GatherVectorInt16SignExtendNonTemporal(mask, addresses); + + /// + /// svint64_t svldnt1sh_gather[_u64base]_s64(svbool_t pg, svuint64_t bases) + /// LDNT1SH Zresult.D, Pg/Z, [Zbases.D, XZR] + /// + public static unsafe Vector GatherVectorInt16SignExtendNonTemporal(Vector mask, Vector addresses) => GatherVectorInt16SignExtendNonTemporal(mask, addresses); + + /// + /// svint64_t svldnt1sh_gather_[s64]index_s64(svbool_t pg, const int16_t *base, svint64_t indices) + /// LDNT1SH Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorInt16SignExtendNonTemporal(Vector mask, short* address, Vector indices) => GatherVectorInt16SignExtendNonTemporal(mask, address, indices); + + /// + /// svint64_t svldnt1sh_gather_[u64]index_s64(svbool_t pg, const int16_t *base, svuint64_t indices) + /// LDNT1SH Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorInt16SignExtendNonTemporal(Vector mask, short* address, Vector indices) => GatherVectorInt16SignExtendNonTemporal(mask, address, indices); + + // + // svuint32_t svldnt1sh_gather[_u32base]_u32(svbool_t pg, svuint32_t bases) + // LDNT1SH Zresult.S, Pg/Z, [Zbases.S, XZR] + // + // Removed as per #103297 + // public static unsafe Vector GatherVectorInt16SignExtendNonTemporal(Vector mask, Vector addresses) => GatherVectorInt16SignExtendNonTemporal(mask, addresses); + + /// + /// svuint64_t svldnt1sh_gather[_u64base]_u64(svbool_t pg, svuint64_t bases) + /// LDNT1SH Zresult.D, Pg/Z, [Zbases.D, XZR] + /// + public static unsafe Vector GatherVectorInt16SignExtendNonTemporal(Vector mask, Vector addresses) => GatherVectorInt16SignExtendNonTemporal(mask, addresses); + + /// + /// svuint64_t svldnt1sh_gather_[s64]index_u64(svbool_t pg, const int16_t *base, svint64_t indices) + /// LDNT1SH Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorInt16SignExtendNonTemporal(Vector mask, short* address, Vector indices) => GatherVectorInt16SignExtendNonTemporal(mask, address, indices); + + /// + /// svuint64_t svldnt1sh_gather_[u64]index_u64(svbool_t pg, const int16_t *base, svuint64_t indices) + /// LDNT1SH Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorInt16SignExtendNonTemporal(Vector mask, short* address, Vector indices) => GatherVectorInt16SignExtendNonTemporal(mask, address, indices); + + + // Load 16-bit data and sign-extend, non-temporal + + /// + /// svint32_t svldnt1sh_gather_[u32]offset_s32(svbool_t pg, const int16_t *base, svuint32_t offsets) + /// LDNT1SH Zresult.S, Pg/Z, [Zoffsets.S, Xbase] + /// + public static unsafe Vector GatherVectorInt16WithByteOffsetsSignExtendNonTemporal(Vector mask, short* address, Vector offsets) => GatherVectorInt16WithByteOffsetsSignExtendNonTemporal(mask, address, offsets); + + /// + /// svint64_t svldnt1sh_gather_[s64]offset_s64(svbool_t pg, const int16_t *base, svint64_t offsets) + /// LDNT1SH Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorInt16WithByteOffsetsSignExtendNonTemporal(Vector mask, short* address, Vector offsets) => GatherVectorInt16WithByteOffsetsSignExtendNonTemporal(mask, address, offsets); + + /// + /// svint64_t svldnt1sh_gather_[u64]offset_s64(svbool_t pg, const int16_t *base, svuint64_t offsets) + /// LDNT1SH Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorInt16WithByteOffsetsSignExtendNonTemporal(Vector mask, short* address, Vector offsets) => GatherVectorInt16WithByteOffsetsSignExtendNonTemporal(mask, address, offsets); + + /// + /// svuint32_t svldnt1sh_gather_[u32]offset_u32(svbool_t pg, const int16_t *base, svuint32_t offsets) + /// LDNT1SH Zresult.S, Pg/Z, [Zoffsets.S, Xbase] + /// + public static unsafe Vector GatherVectorInt16WithByteOffsetsSignExtendNonTemporal(Vector mask, short* address, Vector offsets) => GatherVectorInt16WithByteOffsetsSignExtendNonTemporal(mask, address, offsets); + + /// + /// svuint64_t svldnt1sh_gather_[s64]offset_u64(svbool_t pg, const int16_t *base, svint64_t offsets) + /// LDNT1SH Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorInt16WithByteOffsetsSignExtendNonTemporal(Vector mask, short* address, Vector offsets) => GatherVectorInt16WithByteOffsetsSignExtendNonTemporal(mask, address, offsets); + + /// + /// svuint64_t svldnt1sh_gather_[u64]offset_u64(svbool_t pg, const int16_t *base, svuint64_t offsets) + /// LDNT1SH Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorInt16WithByteOffsetsSignExtendNonTemporal(Vector mask, short* address, Vector offsets) => GatherVectorInt16WithByteOffsetsSignExtendNonTemporal(mask, address, offsets); + + + // Load 32-bit data and sign-extend, non-temporal + + /// + /// svint64_t svldnt1sw_gather[_u64base]_s64(svbool_t pg, svuint64_t bases) + /// LDNT1SW Zresult.D, Pg/Z, [Zbases.D, XZR] + /// + public static unsafe Vector GatherVectorInt32SignExtendNonTemporal(Vector mask, Vector addresses) => GatherVectorInt32SignExtendNonTemporal(mask, addresses); + + /// + /// svint64_t svldnt1sw_gather_[s64]index_s64(svbool_t pg, const int32_t *base, svint64_t indices) + /// LDNT1SW Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorInt32SignExtendNonTemporal(Vector mask, int* address, Vector indices) => GatherVectorInt32SignExtendNonTemporal(mask, address, indices); + + /// + /// svint64_t svldnt1sw_gather_[u64]index_s64(svbool_t pg, const int32_t *base, svuint64_t indices) + /// LDNT1SW Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorInt32SignExtendNonTemporal(Vector mask, int* address, Vector indices) => GatherVectorInt32SignExtendNonTemporal(mask, address, indices); + + /// + /// svuint64_t svldnt1sw_gather[_u64base]_u64(svbool_t pg, svuint64_t bases) + /// LDNT1SW Zresult.D, Pg/Z, [Zbases.D, XZR] + /// + public static unsafe Vector GatherVectorInt32SignExtendNonTemporal(Vector mask, Vector addresses) => GatherVectorInt32SignExtendNonTemporal(mask, addresses); + + /// + /// svuint64_t svldnt1sw_gather_[s64]index_u64(svbool_t pg, const int32_t *base, svint64_t indices) + /// LDNT1SW Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorInt32SignExtendNonTemporal(Vector mask, int* address, Vector indices) => GatherVectorInt32SignExtendNonTemporal(mask, address, indices); + + /// + /// svuint64_t svldnt1sw_gather_[u64]index_u64(svbool_t pg, const int32_t *base, svuint64_t indices) + /// LDNT1SW Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorInt32SignExtendNonTemporal(Vector mask, int* address, Vector indices) => GatherVectorInt32SignExtendNonTemporal(mask, address, indices); + + + // Load 32-bit data and sign-extend, non-temporal + + /// + /// svint64_t svldnt1sw_gather_[s64]offset_s64(svbool_t pg, const int32_t *base, svint64_t offsets) + /// LDNT1SW Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorInt32WithByteOffsetsSignExtendNonTemporal(Vector mask, int* address, Vector offsets) => GatherVectorInt32WithByteOffsetsSignExtendNonTemporal(mask, address, offsets); + + /// + /// svint64_t svldnt1sw_gather_[u64]offset_s64(svbool_t pg, const int32_t *base, svuint64_t offsets) + /// LDNT1SW Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorInt32WithByteOffsetsSignExtendNonTemporal(Vector mask, int* address, Vector offsets) => GatherVectorInt32WithByteOffsetsSignExtendNonTemporal(mask, address, offsets); + + /// + /// svuint64_t svldnt1sw_gather_[s64]offset_u64(svbool_t pg, const int32_t *base, svint64_t offsets) + /// LDNT1SW Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorInt32WithByteOffsetsSignExtendNonTemporal(Vector mask, int* address, Vector offsets) => GatherVectorInt32WithByteOffsetsSignExtendNonTemporal(mask, address, offsets); + + /// + /// svuint64_t svldnt1sw_gather_[u64]offset_u64(svbool_t pg, const int32_t *base, svuint64_t offsets) + /// LDNT1SW Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorInt32WithByteOffsetsSignExtendNonTemporal(Vector mask, int* address, Vector offsets) => GatherVectorInt32WithByteOffsetsSignExtendNonTemporal(mask, address, offsets); + + + // Unextended load, non-temporal + + /// + /// svfloat64_t svldnt1_gather[_u64base]_f64(svbool_t pg, svuint64_t bases) + /// LDNT1D Zresult.D, Pg/Z, [Zbases.D, XZR] + /// + public static unsafe Vector GatherVectorNonTemporal(Vector mask, Vector addresses) => GatherVectorNonTemporal(mask, addresses); + + /// + /// svfloat64_t svldnt1_gather_[s64]index[_f64](svbool_t pg, const float64_t *base, svint64_t indices) + /// LDNT1D Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorNonTemporal(Vector mask, double* address, Vector indices) => GatherVectorNonTemporal(mask, address, indices); + + /// + /// svfloat64_t svldnt1_gather_[u64]index[_f64](svbool_t pg, const float64_t *base, svuint64_t indices) + /// LDNT1D Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorNonTemporal(Vector mask, double* address, Vector indices) => GatherVectorNonTemporal(mask, address, indices); + + // + // svint32_t svldnt1_gather[_u32base]_s32(svbool_t pg, svuint32_t bases) + // LDNT1W Zresult.S, Pg/Z, [Zbases.S, XZR] + // + // Removed as per #103297 + // public static unsafe Vector GatherVectorNonTemporal(Vector mask, Vector addresses) => GatherVectorNonTemporal(mask, addresses); + + /// + /// svint64_t svldnt1_gather[_u64base]_s64(svbool_t pg, svuint64_t bases) + /// LDNT1D Zresult.D, Pg/Z, [Zbases.D, XZR] + /// + public static unsafe Vector GatherVectorNonTemporal(Vector mask, Vector addresses) => GatherVectorNonTemporal(mask, addresses); + + /// + /// svint64_t svldnt1_gather_[s64]index[_s64](svbool_t pg, const int64_t *base, svint64_t indices) + /// LDNT1D Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorNonTemporal(Vector mask, long* address, Vector indices) => GatherVectorNonTemporal(mask, address, indices); + + /// + /// svint64_t svldnt1_gather_[u64]index[_s64](svbool_t pg, const int64_t *base, svuint64_t indices) + /// LDNT1D Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorNonTemporal(Vector mask, long* address, Vector indices) => GatherVectorNonTemporal(mask, address, indices); + + // + // svfloat32_t svldnt1_gather[_u32base]_f32(svbool_t pg, svuint32_t bases) + // LDNT1W Zresult.S, Pg/Z, [Zbases.S, XZR] + // + // Removed as per #103297 + // public static unsafe Vector GatherVectorNonTemporal(Vector mask, Vector addresses) => GatherVectorNonTemporal(mask, addresses); + + // + // svuint32_t svldnt1_gather[_u32base]_u32(svbool_t pg, svuint32_t bases) + // LDNT1W Zresult.S, Pg/Z, [Zbases.S, XZR] + // + // Removed as per #103297 + // public static unsafe Vector GatherVectorNonTemporal(Vector mask, Vector addresses) => GatherVectorNonTemporal(mask, addresses); + + /// + /// svuint64_t svldnt1_gather[_u64base]_u64(svbool_t pg, svuint64_t bases) + /// LDNT1D Zresult.D, Pg/Z, [Zbases.D, XZR] + /// + public static unsafe Vector GatherVectorNonTemporal(Vector mask, Vector addresses) => GatherVectorNonTemporal(mask, addresses); + + /// + /// svuint64_t svldnt1_gather_[s64]index[_u64](svbool_t pg, const uint64_t *base, svint64_t indices) + /// LDNT1D Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorNonTemporal(Vector mask, ulong* address, Vector indices) => GatherVectorNonTemporal(mask, address, indices); + + /// + /// svuint64_t svldnt1_gather_[u64]index[_u64](svbool_t pg, const uint64_t *base, svuint64_t indices) + /// LDNT1D Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorNonTemporal(Vector mask, ulong* address, Vector indices) => GatherVectorNonTemporal(mask, address, indices); + + /// + /// svfloat64_t svldnt1_gather_[s64]offset[_f64](svbool_t pg, const float64_t *base, svint64_t offsets) + /// LDNT1D Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorWithByteOffsetsNonTemporal(Vector mask, double* address, Vector offsets) => GatherVectorWithByteOffsetsNonTemporal(mask, address, offsets); + + /// + /// svfloat64_t svldnt1_gather_[u64]offset[_f64](svbool_t pg, const float64_t *base, svuint64_t offsets) + /// LDNT1D Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorWithByteOffsetsNonTemporal(Vector mask, double* address, Vector offsets) => GatherVectorWithByteOffsetsNonTemporal(mask, address, offsets); + + /// + /// svint32_t svldnt1_gather_[u32]offset[_s32](svbool_t pg, const int32_t *base, svuint32_t offsets) + /// LDNT1W Zresult.S, Pg/Z, [Zoffsets.S, Xbase] + /// + public static unsafe Vector GatherVectorWithByteOffsetsNonTemporal(Vector mask, int* address, Vector offsets) => GatherVectorWithByteOffsetsNonTemporal(mask, address, offsets); + + /// + /// svint64_t svldnt1_gather_[s64]offset[_s64](svbool_t pg, const int64_t *base, svint64_t offsets) + /// LDNT1D Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorWithByteOffsetsNonTemporal(Vector mask, long* address, Vector offsets) => GatherVectorWithByteOffsetsNonTemporal(mask, address, offsets); + + /// + /// svint64_t svldnt1_gather_[u64]offset[_s64](svbool_t pg, const int64_t *base, svuint64_t offsets) + /// LDNT1D Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorWithByteOffsetsNonTemporal(Vector mask, long* address, Vector offsets) => GatherVectorWithByteOffsetsNonTemporal(mask, address, offsets); + + /// + /// svfloat32_t svldnt1_gather_[u32]offset[_f32](svbool_t pg, const float32_t *base, svuint32_t offsets) + /// LDNT1W Zresult.S, Pg/Z, [Zoffsets.S, Xbase] + /// + public static unsafe Vector GatherVectorWithByteOffsetsNonTemporal(Vector mask, float* address, Vector offsets) => GatherVectorWithByteOffsetsNonTemporal(mask, address, offsets); + + /// + /// svuint32_t svldnt1_gather_[u32]offset[_u32](svbool_t pg, const uint32_t *base, svuint32_t offsets) + /// LDNT1W Zresult.S, Pg/Z, [Zoffsets.S, Xbase] + /// + public static unsafe Vector GatherVectorWithByteOffsetsNonTemporal(Vector mask, uint* address, Vector offsets) => GatherVectorWithByteOffsetsNonTemporal(mask, address, offsets); + + /// + /// svuint64_t svldnt1_gather_[s64]offset[_u64](svbool_t pg, const uint64_t *base, svint64_t offsets) + /// LDNT1D Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorWithByteOffsetsNonTemporal(Vector mask, ulong* address, Vector offsets) => GatherVectorWithByteOffsetsNonTemporal(mask, address, offsets); + + /// + /// svuint64_t svldnt1_gather_[u64]offset[_u64](svbool_t pg, const uint64_t *base, svuint64_t offsets) + /// LDNT1D Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorWithByteOffsetsNonTemporal(Vector mask, ulong* address, Vector offsets) => GatherVectorWithByteOffsetsNonTemporal(mask, address, offsets); + + + // Load 8-bit data and sign-extend, non-temporal + + // + // svint32_t svldnt1sb_gather[_u32base]_s32(svbool_t pg, svuint32_t bases) + // LDNT1SB Zresult.S, Pg/Z, [Zbases.S, XZR] + // + // Removed as per #103297 + // public static unsafe Vector GatherVectorSByteSignExtendNonTemporal(Vector mask, Vector addresses) => GatherVectorSByteSignExtendNonTemporal(mask, addresses); + + /// + /// svint32_t svldnt1sb_gather_[u32]offset_s32(svbool_t pg, const int8_t *base, svuint32_t offsets) + /// LDNT1SB Zresult.S, Pg/Z, [Zoffsets.S, Xbase] + /// + public static unsafe Vector GatherVectorSByteSignExtendNonTemporal(Vector mask, sbyte* address, Vector offsets) => GatherVectorSByteSignExtendNonTemporal(mask, address, offsets); + + /// + /// svint64_t svldnt1sb_gather[_u64base]_s64(svbool_t pg, svuint64_t bases) + /// LDNT1SB Zresult.D, Pg/Z, [Zbases.D, XZR] + /// + public static unsafe Vector GatherVectorSByteSignExtendNonTemporal(Vector mask, Vector addresses) => GatherVectorSByteSignExtendNonTemporal(mask, addresses); + + /// + /// svint64_t svldnt1sb_gather_[s64]offset_s64(svbool_t pg, const int8_t *base, svint64_t offsets) + /// LDNT1SB Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorSByteSignExtendNonTemporal(Vector mask, sbyte* address, Vector offsets) => GatherVectorSByteSignExtendNonTemporal(mask, address, offsets); + + /// + /// svint64_t svldnt1sb_gather_[u64]offset_s64(svbool_t pg, const int8_t *base, svuint64_t offsets) + /// LDNT1SB Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorSByteSignExtendNonTemporal(Vector mask, sbyte* address, Vector offsets) => GatherVectorSByteSignExtendNonTemporal(mask, address, offsets); + + // + // svuint32_t svldnt1sb_gather[_u32base]_u32(svbool_t pg, svuint32_t bases) + // LDNT1SB Zresult.S, Pg/Z, [Zbases.S, XZR] + // + // Removed as per #103297 + // public static unsafe Vector GatherVectorSByteSignExtendNonTemporal(Vector mask, Vector addresses) => GatherVectorSByteSignExtendNonTemporal(mask, addresses); + + /// + /// svuint32_t svldnt1sb_gather_[u32]offset_u32(svbool_t pg, const int8_t *base, svuint32_t offsets) + /// LDNT1SB Zresult.S, Pg/Z, [Zoffsets.S, Xbase] + /// + public static unsafe Vector GatherVectorSByteSignExtendNonTemporal(Vector mask, sbyte* address, Vector offsets) => GatherVectorSByteSignExtendNonTemporal(mask, address, offsets); + + /// + /// svuint64_t svldnt1sb_gather[_u64base]_u64(svbool_t pg, svuint64_t bases) + /// LDNT1SB Zresult.D, Pg/Z, [Zbases.D, XZR] + /// + public static unsafe Vector GatherVectorSByteSignExtendNonTemporal(Vector mask, Vector addresses) => GatherVectorSByteSignExtendNonTemporal(mask, addresses); + + /// + /// svuint64_t svldnt1sb_gather_[s64]offset_u64(svbool_t pg, const int8_t *base, svint64_t offsets) + /// LDNT1SB Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorSByteSignExtendNonTemporal(Vector mask, sbyte* address, Vector offsets) => GatherVectorSByteSignExtendNonTemporal(mask, address, offsets); + + /// + /// svuint64_t svldnt1sb_gather_[u64]offset_u64(svbool_t pg, const int8_t *base, svuint64_t offsets) + /// LDNT1SB Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorSByteSignExtendNonTemporal(Vector mask, sbyte* address, Vector offsets) => GatherVectorSByteSignExtendNonTemporal(mask, address, offsets); + + + // Load 16-bit data and zero-extend, non-temporal + + /// + /// svint32_t svldnt1uh_gather_[u32]offset_s32(svbool_t pg, const uint16_t *base, svuint32_t offsets) + /// LDNT1H Zresult.S, Pg/Z, [Zoffsets.S, Xbase] + /// + public static unsafe Vector GatherVectorUInt16WithByteOffsetsZeroExtendNonTemporal(Vector mask, ushort* address, Vector offsets) => GatherVectorUInt16WithByteOffsetsZeroExtendNonTemporal(mask, address, offsets); + + /// + /// svint64_t svldnt1uh_gather_[s64]offset_s64(svbool_t pg, const uint16_t *base, svint64_t offsets) + /// LDNT1H Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorUInt16WithByteOffsetsZeroExtendNonTemporal(Vector mask, ushort* address, Vector offsets) => GatherVectorUInt16WithByteOffsetsZeroExtendNonTemporal(mask, address, offsets); + + /// + /// svint64_t svldnt1uh_gather_[u64]offset_s64(svbool_t pg, const uint16_t *base, svuint64_t offsets) + /// LDNT1H Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorUInt16WithByteOffsetsZeroExtendNonTemporal(Vector mask, ushort* address, Vector offsets) => GatherVectorUInt16WithByteOffsetsZeroExtendNonTemporal(mask, address, offsets); + + /// + /// svuint32_t svldnt1uh_gather_[u32]offset_u32(svbool_t pg, const uint16_t *base, svuint32_t offsets) + /// LDNT1H Zresult.S, Pg/Z, [Zoffsets.S, Xbase] + /// + public static unsafe Vector GatherVectorUInt16WithByteOffsetsZeroExtendNonTemporal(Vector mask, ushort* address, Vector offsets) => GatherVectorUInt16WithByteOffsetsZeroExtendNonTemporal(mask, address, offsets); + + /// + /// svuint64_t svldnt1uh_gather_[s64]offset_u64(svbool_t pg, const uint16_t *base, svint64_t offsets) + /// LDNT1H Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorUInt16WithByteOffsetsZeroExtendNonTemporal(Vector mask, ushort* address, Vector offsets) => GatherVectorUInt16WithByteOffsetsZeroExtendNonTemporal(mask, address, offsets); + + /// + /// svuint64_t svldnt1uh_gather_[u64]offset_u64(svbool_t pg, const uint16_t *base, svuint64_t offsets) + /// LDNT1H Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorUInt16WithByteOffsetsZeroExtendNonTemporal(Vector mask, ushort* address, Vector offsets) => GatherVectorUInt16WithByteOffsetsZeroExtendNonTemporal(mask, address, offsets); + + + // Load 16-bit data and zero-extend, non-temporal + + // + // svint32_t svldnt1uh_gather[_u32base]_s32(svbool_t pg, svuint32_t bases) + // LDNT1H Zresult.S, Pg/Z, [Zbases.S, XZR] + // + // Removed as per #103297 + // public static unsafe Vector GatherVectorUInt16ZeroExtendNonTemporal(Vector mask, Vector addresses) => GatherVectorUInt16ZeroExtendNonTemporal(mask, addresses); + + /// + /// svint64_t svldnt1uh_gather[_u64base]_s64(svbool_t pg, svuint64_t bases) + /// LDNT1H Zresult.D, Pg/Z, [Zbases.D, XZR] + /// + public static unsafe Vector GatherVectorUInt16ZeroExtendNonTemporal(Vector mask, Vector addresses) => GatherVectorUInt16ZeroExtendNonTemporal(mask, addresses); + + /// + /// svint64_t svldnt1uh_gather_[s64]index_s64(svbool_t pg, const uint16_t *base, svint64_t indices) + /// LDNT1H Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorUInt16ZeroExtendNonTemporal(Vector mask, ushort* address, Vector indices) => GatherVectorUInt16ZeroExtendNonTemporal(mask, address, indices); + + /// + /// svint64_t svldnt1uh_gather_[u64]index_s64(svbool_t pg, const uint16_t *base, svuint64_t indices) + /// LDNT1H Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorUInt16ZeroExtendNonTemporal(Vector mask, ushort* address, Vector indices) => GatherVectorUInt16ZeroExtendNonTemporal(mask, address, indices); + + // + // svuint32_t svldnt1uh_gather[_u32base]_u32(svbool_t pg, svuint32_t bases) + // LDNT1H Zresult.S, Pg/Z, [Zbases.S, XZR] + // + // Removed as per #103297 + // public static unsafe Vector GatherVectorUInt16ZeroExtendNonTemporal(Vector mask, Vector addresses) => GatherVectorUInt16ZeroExtendNonTemporal(mask, addresses); + + /// + /// svuint64_t svldnt1uh_gather[_u64base]_u64(svbool_t pg, svuint64_t bases) + /// LDNT1H Zresult.D, Pg/Z, [Zbases.D, XZR] + /// + public static unsafe Vector GatherVectorUInt16ZeroExtendNonTemporal(Vector mask, Vector addresses) => GatherVectorUInt16ZeroExtendNonTemporal(mask, addresses); + + /// + /// svuint64_t svldnt1uh_gather_[s64]index_u64(svbool_t pg, const uint16_t *base, svint64_t indices) + /// LDNT1H Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorUInt16ZeroExtendNonTemporal(Vector mask, ushort* address, Vector indices) => GatherVectorUInt16ZeroExtendNonTemporal(mask, address, indices); + + /// + /// svuint64_t svldnt1uh_gather_[u64]index_u64(svbool_t pg, const uint16_t *base, svuint64_t indices) + /// LDNT1H Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorUInt16ZeroExtendNonTemporal(Vector mask, ushort* address, Vector indices) => GatherVectorUInt16ZeroExtendNonTemporal(mask, address, indices); + + + // Load 32-bit data and zero-extend, non-temporal + + /// + /// svint64_t svldnt1uw_gather_[s64]offset_s64(svbool_t pg, const uint32_t *base, svint64_t offsets) + /// LDNT1W Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorUInt32WithByteOffsetsZeroExtendNonTemporal(Vector mask, uint* address, Vector offsets) => GatherVectorUInt32WithByteOffsetsZeroExtendNonTemporal(mask, address, offsets); + + /// + /// svint64_t svldnt1uw_gather_[u64]offset_s64(svbool_t pg, const uint32_t *base, svuint64_t offsets) + /// LDNT1W Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorUInt32WithByteOffsetsZeroExtendNonTemporal(Vector mask, uint* address, Vector offsets) => GatherVectorUInt32WithByteOffsetsZeroExtendNonTemporal(mask, address, offsets); + + /// + /// svuint64_t svldnt1uw_gather_[s64]offset_u64(svbool_t pg, const uint32_t *base, svint64_t offsets) + /// LDNT1W Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorUInt32WithByteOffsetsZeroExtendNonTemporal(Vector mask, uint* address, Vector offsets) => GatherVectorUInt32WithByteOffsetsZeroExtendNonTemporal(mask, address, offsets); + + /// + /// svuint64_t svldnt1uw_gather_[u64]offset_u64(svbool_t pg, const uint32_t *base, svuint64_t offsets) + /// LDNT1W Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorUInt32WithByteOffsetsZeroExtendNonTemporal(Vector mask, uint* address, Vector offsets) => GatherVectorUInt32WithByteOffsetsZeroExtendNonTemporal(mask, address, offsets); + + + // Load 32-bit data and zero-extend, non-temporal + + /// + /// svint64_t svldnt1uw_gather[_u64base]_s64(svbool_t pg, svuint64_t bases) + /// LDNT1W Zresult.D, Pg/Z, [Zbases.D, XZR] + /// + public static unsafe Vector GatherVectorUInt32ZeroExtendNonTemporal(Vector mask, Vector addresses) => GatherVectorUInt32ZeroExtendNonTemporal(mask, addresses); + + /// + /// svint64_t svldnt1uw_gather_[s64]index_s64(svbool_t pg, const uint32_t *base, svint64_t indices) + /// LDNT1W Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorUInt32ZeroExtendNonTemporal(Vector mask, uint* address, Vector indices) => GatherVectorUInt32ZeroExtendNonTemporal(mask, address, indices); + + /// + /// svint64_t svldnt1uw_gather_[u64]index_s64(svbool_t pg, const uint32_t *base, svuint64_t indices) + /// LDNT1W Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorUInt32ZeroExtendNonTemporal(Vector mask, uint* address, Vector indices) => GatherVectorUInt32ZeroExtendNonTemporal(mask, address, indices); + + /// + /// svuint64_t svldnt1uw_gather[_u64base]_u64(svbool_t pg, svuint64_t bases) + /// LDNT1W Zresult.D, Pg/Z, [Zbases.D, XZR] + /// + public static unsafe Vector GatherVectorUInt32ZeroExtendNonTemporal(Vector mask, Vector addresses) => GatherVectorUInt32ZeroExtendNonTemporal(mask, addresses); + + /// + /// svuint64_t svldnt1uw_gather_[s64]index_u64(svbool_t pg, const uint32_t *base, svint64_t indices) + /// LDNT1W Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorUInt32ZeroExtendNonTemporal(Vector mask, uint* address, Vector indices) => GatherVectorUInt32ZeroExtendNonTemporal(mask, address, indices); + + /// + /// svuint64_t svldnt1uw_gather_[u64]index_u64(svbool_t pg, const uint32_t *base, svuint64_t indices) + /// LDNT1W Zresult.D, Pg/Z, [Zoffsets.D, Xbase] + /// + public static unsafe Vector GatherVectorUInt32ZeroExtendNonTemporal(Vector mask, uint* address, Vector indices) => GatherVectorUInt32ZeroExtendNonTemporal(mask, address, indices); + + /// Interleaving Xor /// diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Analyzers/ComClassGeneratorDiagnosticsAnalyzer.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Analyzers/ComClassGeneratorDiagnosticsAnalyzer.cs new file mode 100644 index 00000000000000..35952e323a5db2 --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Analyzers/ComClassGeneratorDiagnosticsAnalyzer.cs @@ -0,0 +1,106 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.DotnetRuntime.Extensions; + +namespace Microsoft.Interop.Analyzers; + +[DiagnosticAnalyzer(LanguageNames.CSharp)] +public sealed class ComClassGeneratorDiagnosticsAnalyzer : DiagnosticAnalyzer +{ + public override ImmutableArray SupportedDiagnostics { get; } = + ImmutableArray.Create( + GeneratorDiagnostics.RequiresAllowUnsafeBlocks, + GeneratorDiagnostics.InvalidAttributedClassMissingPartialModifier, + GeneratorDiagnostics.ClassDoesNotImplementAnyGeneratedComInterface); + + public override void Initialize(AnalysisContext context) + { + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); + context.EnableConcurrentExecution(); + + context.RegisterCompilationStartAction(static context => + { + bool unsafeCodeIsEnabled = context.Compilation.Options is CSharpCompilationOptions { AllowUnsafe: true }; + INamedTypeSymbol? generatedComClassAttributeType = context.Compilation.GetBestTypeByMetadataName(TypeNames.GeneratedComClassAttribute); + + // We use this type only to report warning diagnostic. We also don't report a warning if there is at least one error. + // Given that with unsafe code disabled we will get an error on each declaration, we can skip + // unnecessary work of getting this symbol here + INamedTypeSymbol? generatedComInterfaceAttributeType = unsafeCodeIsEnabled + ? context.Compilation.GetBestTypeByMetadataName(TypeNames.GeneratedComInterfaceAttribute) + : null; + + context.RegisterSymbolAction(context => AnalyzeNamedType(context, unsafeCodeIsEnabled, generatedComClassAttributeType, generatedComInterfaceAttributeType), SymbolKind.NamedType); + }); + } + + private static void AnalyzeNamedType(SymbolAnalysisContext context, bool unsafeCodeIsEnabled, INamedTypeSymbol? generatedComClassAttributeType, INamedTypeSymbol? generatedComInterfaceAttributeType) + { + if (context.Symbol is not INamedTypeSymbol { TypeKind: TypeKind.Class } classToAnalyze) + { + return; + } + + if (!classToAnalyze.GetAttributes().Any(a => SymbolEqualityComparer.Default.Equals(a.AttributeClass, generatedComClassAttributeType))) + { + return; + } + + foreach (Diagnostic diagnostic in GetDiagnosticsForAnnotatedClass(classToAnalyze, unsafeCodeIsEnabled, generatedComInterfaceAttributeType)) + { + context.ReportDiagnostic(diagnostic); + } + } + + public static IEnumerable GetDiagnosticsForAnnotatedClass(INamedTypeSymbol annotatedClass, bool unsafeCodeIsEnabled, INamedTypeSymbol? generatedComInterfaceAttributeType) + { + Location location = annotatedClass.Locations.First(); + bool hasErrors = false; + + if (!unsafeCodeIsEnabled) + { + yield return Diagnostic.Create(GeneratorDiagnostics.RequiresAllowUnsafeBlocks, location); + hasErrors = true; + } + + var declarationNode = (TypeDeclarationSyntax)location.SourceTree.GetRoot().FindNode(location.SourceSpan); + + if (!declarationNode.IsInPartialContext(out _)) + { + yield return Diagnostic.Create( + GeneratorDiagnostics.InvalidAttributedClassMissingPartialModifier, + location, + annotatedClass); + hasErrors = true; + } + + if (hasErrors) + { + // If we already reported at least one error avoid stacking a warning on top of it + yield break; + } + + foreach (INamedTypeSymbol iface in annotatedClass.AllInterfaces) + { + if (iface.GetAttributes().FirstOrDefault(a => SymbolEqualityComparer.Default.Equals(a.AttributeClass, generatedComInterfaceAttributeType)) is { } generatedComInterfaceAttribute && + GeneratedComInterfaceCompilationData.GetDataFromAttribute(generatedComInterfaceAttribute).Options.HasFlag(ComInterfaceOptions.ManagedObjectWrapper)) + { + yield break; + } + } + + // Class doesn't implement any generated COM interface. Report a warning about that + yield return Diagnostic.Create( + GeneratorDiagnostics.ClassDoesNotImplementAnyGeneratedComInterface, + location, + annotatedClass); + } +} diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComClassGenerator.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComClassGenerator.cs index 1455804b0ba9db..4f8940ca0df19f 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComClassGenerator.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComClassGenerator.cs @@ -8,6 +8,8 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.DotnetRuntime.Extensions; +using Microsoft.Interop.Analyzers; using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; using static Microsoft.Interop.SyntaxFactoryExtensions; @@ -18,24 +20,28 @@ public class ComClassGenerator : IIncrementalGenerator { public void Initialize(IncrementalGeneratorInitializationContext context) { - var unsafeCodeIsEnabled = context.CompilationProvider.Select((comp, ct) => comp.Options is CSharpCompilationOptions { AllowUnsafe: true }); // Unsafe code enabled // Get all types with the [GeneratedComClassAttribute] attribute. - var attributedClassesOrDiagnostics = context.SyntaxProvider + var attributedClasses = context.SyntaxProvider .ForAttributeWithMetadataName( TypeNames.GeneratedComClassAttribute, static (node, ct) => node is ClassDeclarationSyntax, - static (context, ct) => context) - .Combine(unsafeCodeIsEnabled) - .Select(static (data, ct) => + static (context, _) => { - var context = data.Left; - var unsafeCodeIsEnabled = data.Right; var type = (INamedTypeSymbol)context.TargetSymbol; var syntax = (ClassDeclarationSyntax)context.TargetNode; - return ComClassInfo.From(type, syntax, unsafeCodeIsEnabled); - }); + var compilation = context.SemanticModel.Compilation; + var unsafeCodeIsEnabled = compilation.Options is CSharpCompilationOptions { AllowUnsafe: true }; + INamedTypeSymbol? generatedComInterfaceAttributeType = compilation.GetBestTypeByMetadataName(TypeNames.GeneratedComInterfaceAttribute); - var attributedClasses = context.FilterAndReportDiagnostics(attributedClassesOrDiagnostics); + // Currently all reported diagnostics are fatal to the generator + if (ComClassGeneratorDiagnosticsAnalyzer.GetDiagnosticsForAnnotatedClass(type, unsafeCodeIsEnabled, generatedComInterfaceAttributeType).Any()) + { + return null; + } + + return ComClassInfo.From(type, syntax, generatedComInterfaceAttributeType); + }) + .Where(static info => info is not null); var classInfoType = attributedClasses .Select(static (info, ct) => new ItemAndSyntaxes(info, diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComClassInfo.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComClassInfo.cs index 920409ced00f87..838c23c01644bc 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComClassInfo.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComClassInfo.cs @@ -23,26 +23,12 @@ private ComClassInfo(string className, ContainingSyntaxContext containingSyntaxC ImplementedInterfacesNames = implementedInterfacesNames; } - public static DiagnosticOr From(INamedTypeSymbol type, ClassDeclarationSyntax syntax, bool unsafeCodeIsEnabled) + public static ComClassInfo From(INamedTypeSymbol type, ClassDeclarationSyntax syntax, INamedTypeSymbol? generatedComInterfaceAttributeType) { - if (!unsafeCodeIsEnabled) - { - return DiagnosticOr.From(DiagnosticInfo.Create(GeneratorDiagnostics.RequiresAllowUnsafeBlocks, syntax.Identifier.GetLocation())); - } - - if (!syntax.IsInPartialContext(out _)) - { - return DiagnosticOr.From( - DiagnosticInfo.Create( - GeneratorDiagnostics.InvalidAttributedClassMissingPartialModifier, - syntax.Identifier.GetLocation(), - type.ToDisplayString())); - } - ImmutableArray.Builder names = ImmutableArray.CreateBuilder(); foreach (INamedTypeSymbol iface in type.AllInterfaces) { - AttributeData? generatedComInterfaceAttribute = iface.GetAttributes().FirstOrDefault(attr => attr.AttributeClass?.ToDisplayString() == TypeNames.GeneratedComInterfaceAttribute); + AttributeData? generatedComInterfaceAttribute = iface.GetAttributes().FirstOrDefault(attr => SymbolEqualityComparer.Default.Equals(attr.AttributeClass, generatedComInterfaceAttributeType)); if (generatedComInterfaceAttribute is not null) { var attributeData = GeneratedComInterfaceCompilationData.GetDataFromAttribute(generatedComInterfaceAttribute); @@ -53,19 +39,11 @@ public static DiagnosticOr From(INamedTypeSymbol type, ClassDeclar } } - if (names.Count == 0) - { - return DiagnosticOr.From(DiagnosticInfo.Create(GeneratorDiagnostics.ClassDoesNotImplementAnyGeneratedComInterface, - syntax.Identifier.GetLocation(), - type.ToDisplayString())); - } - - return DiagnosticOr.From( - new ComClassInfo( - type.ToDisplayString(), - new ContainingSyntaxContext(syntax), - new ContainingSyntax(syntax.Modifiers, syntax.Kind(), syntax.Identifier, syntax.TypeParameterList), - new(names.ToImmutable()))); + return new ComClassInfo( + type.ToDisplayString(), + new ContainingSyntaxContext(syntax), + new ContainingSyntax(syntax.Modifiers, syntax.Kind(), syntax.Identifier, syntax.TypeParameterList), + new(names.ToImmutable())); } public bool Equals(ComClassInfo? other) diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/DiagnosticOr.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/DiagnosticOr.cs index 2fe420651f7338..0c36ae2c82ce83 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/DiagnosticOr.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/DiagnosticOr.cs @@ -2,11 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; -using System.Linq; -using Microsoft.CodeAnalysis; namespace Microsoft.Interop { @@ -88,27 +85,4 @@ public static DiagnosticOr From(T value, params DiagnosticInfo[] diagnostics) return new ValueAndDiagnostic(value, ImmutableArray.Create(diagnostics)); } } - - public static class DiagnosticOrTHelperExtensions - { - /// - /// Splits the elements of into a values provider and a diagnostics provider. - /// - public static (IncrementalValuesProvider, IncrementalValuesProvider) Split(this IncrementalValuesProvider> provider) - { - var values = provider.Where(x => x.HasValue).Select(static (x, ct) => x.Value); - var diagnostics = provider.Where(x => x.HasDiagnostic).SelectMany(static (x, ct) => x.Diagnostics); - return (values, diagnostics); - } - - /// - /// Filters the by whether or not the is a , reports the diagnostics, and returns the values. - /// - public static IncrementalValuesProvider FilterAndReportDiagnostics(this IncrementalGeneratorInitializationContext ctx, IncrementalValuesProvider> diagnosticOrValues) - { - var (values, diagnostics) = diagnosticOrValues.Split(); - ctx.RegisterDiagnostics(diagnostics); - return values; - } - } } diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/IncrementalGeneratorInitializationContextExtensions.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/IncrementalGeneratorInitializationContextExtensions.cs index 88094b0cff8518..5db454c730e068 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/IncrementalGeneratorInitializationContextExtensions.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/IncrementalGeneratorInitializationContextExtensions.cs @@ -1,14 +1,10 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System; -using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; -using System.Reflection; using System.Text; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Diagnostics; namespace Microsoft.Interop { @@ -50,22 +46,6 @@ public static IncrementalValueProvider CreateStubEnvironmentPro new StubEnvironment(data.Left, data.Right)); } - public static void RegisterDiagnostics(this IncrementalGeneratorInitializationContext context, IncrementalValuesProvider diagnostics) - { - context.RegisterSourceOutput(diagnostics.Where(diag => diag is not null), (context, diagnostic) => - { - context.ReportDiagnostic(diagnostic.ToDiagnostic()); - }); - } - - public static void RegisterDiagnostics(this IncrementalGeneratorInitializationContext context, IncrementalValuesProvider diagnostics) - { - context.RegisterSourceOutput(diagnostics.Where(diag => diag is not null), (context, diagnostic) => - { - context.ReportDiagnostic(diagnostic); - }); - } - public static void RegisterConcatenatedSyntaxOutputs(this IncrementalGeneratorInitializationContext context, IncrementalValuesProvider nodes, string fileName) where TNode : SyntaxNode { diff --git a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/ComClassGeneratorDiagnostics.cs b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/ComClassGeneratorDiagnostics.cs index f07e6d16b6322d..c6443b5160553a 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/ComClassGeneratorDiagnostics.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/ComClassGeneratorDiagnostics.cs @@ -7,7 +7,7 @@ using Microsoft.CodeAnalysis.Testing; using Microsoft.Interop; using Xunit; -using VerifyCS = Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier; +using VerifyCS = Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier; namespace ComInterfaceGenerator.Unit.Tests { @@ -27,7 +27,6 @@ partial interface INativeAPI [GeneratedComClass] internal class {|#0:C|} : INativeAPI {} - """; await VerifyCS.VerifySourceGeneratorAsync( @@ -54,7 +53,6 @@ partial interface INativeAPI [GeneratedComClass] internal partial class {|#0:C|} : INativeAPI {} } - """; await VerifyCS.VerifySourceGeneratorAsync( @@ -72,7 +70,7 @@ protected override CompilationOptions CreateCompilationOptions() } [Fact] - public async Task UnsafeCodeNotEnabledWarns() + public async Task UnsafeCodeNotEnabledErrors() { string source = """ using System.Runtime.InteropServices; @@ -88,15 +86,52 @@ internal partial interface INativeAPI [GeneratedComClass] internal partial class {|#0:C|} : INativeAPI {} } + """; + + var test = new UnsafeBlocksNotAllowedTest(false) + { + TestCode = source, + ExpectedDiagnostics = + { + new DiagnosticResult(GeneratorDiagnostics.RequiresAllowUnsafeBlocks) + .WithLocation(0) + } + }; + + await test.RunAsync(); + } + [Fact] + public async Task UnsafeCodeNotEnabledAndNoPartialModifierProducesBothErrors() + { + string source = """ + using System.Runtime.InteropServices; + using System.Runtime.InteropServices.Marshalling; + + public partial class Test + { + [GeneratedComInterface] + internal partial interface INativeAPI + { + } + + [GeneratedComClass] + internal class {|#0:C|} : INativeAPI {} + } """; - var test = new UnsafeBlocksNotAllowedTest(false); - test.TestState.Sources.Add(source); - test.ExpectedDiagnostics.Add( - new DiagnosticResult(GeneratorDiagnostics.RequiresAllowUnsafeBlocks) - .WithLocation(0) - .WithArguments("Test.C")); + var test = new UnsafeBlocksNotAllowedTest(false) + { + TestCode = source, + ExpectedDiagnostics = + { + new DiagnosticResult(GeneratorDiagnostics.RequiresAllowUnsafeBlocks) + .WithLocation(0), + new DiagnosticResult(GeneratorDiagnostics.InvalidAttributedClassMissingPartialModifier) + .WithLocation(0) + .WithArguments("Test.C") + } + }; await test.RunAsync(); } @@ -116,7 +151,6 @@ internal interface INativeAPI [GeneratedComClass] internal partial class {|#0:C|} : INativeAPI {} } - """; await VerifyCS.VerifySourceGeneratorAsync( @@ -125,5 +159,59 @@ await VerifyCS.VerifySourceGeneratorAsync( .WithLocation(0) .WithArguments("Test.C")); } + + [Fact] + public async Task NoWarningIfErrorIsAlreadyPresent_UnsafeCodeNotEnabledError() + { + string source = """ + using System.Runtime.InteropServices; + using System.Runtime.InteropServices.Marshalling; + + public partial class Test{ + internal interface INativeAPI + { + } + + [GeneratedComClass] + internal partial class {|#0:C|} : INativeAPI {} + } + """; + + var test = new UnsafeBlocksNotAllowedTest(false) + { + TestCode = source, + ExpectedDiagnostics = + { + new DiagnosticResult(GeneratorDiagnostics.RequiresAllowUnsafeBlocks) + .WithLocation(0) + } + }; + + await test.RunAsync(); + } + + [Fact] + public async Task NoWarningIfErrorIsAlreadyPresent_NotPartialContextError() + { + string source = """ + using System.Runtime.InteropServices; + using System.Runtime.InteropServices.Marshalling; + + public partial class Test{ + internal interface INativeAPI + { + } + + [GeneratedComClass] + internal class {|#0:C|} : INativeAPI {} + } + """; + + await VerifyCS.VerifySourceGeneratorAsync( + source, + new DiagnosticResult(GeneratorDiagnostics.InvalidAttributedClassMissingPartialModifier) + .WithLocation(0) + .WithArguments("Test.C")); + } } } diff --git a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/ComClassGeneratorOutputShape.cs b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/ComClassGeneratorOutputShape.cs index c61e00b0a3d7e0..1b4dcc94807397 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/ComClassGeneratorOutputShape.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/ComClassGeneratorOutputShape.cs @@ -104,7 +104,7 @@ class GeneratedShapeTest : VerifyCS.Test private readonly string[] _typeNames; public GeneratedShapeTest(params string[] typeNames) - :base(referenceAncillaryInterop: false) + : base(referenceAncillaryInterop: false) { _typeNames = typeNames; } @@ -129,11 +129,9 @@ private static void VerifyShape(Compilation comp, string userDefinedClassMetadat userDefinedClass.GetAttributes(), attr => SymbolEqualityComparer.Default.Equals(attr.AttributeClass?.OriginalDefinition, comExposedClassAttribute)); - Assert.Collection(Assert.IsAssignableFrom(iUnknownDerivedAttribute.AttributeClass).TypeArguments, - infoType => - { - Assert.True(Assert.IsAssignableFrom(infoType).IsFileLocal); - }); + Assert.NotNull(iUnknownDerivedAttribute.AttributeClass); + ITypeSymbol typeArgument = Assert.Single(iUnknownDerivedAttribute.AttributeClass.TypeArguments); + Assert.True(Assert.IsType(typeArgument, exactMatch: false).IsFileLocal); } } } diff --git a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs index ee67d484124c9f..afb5c1bd6a59f2 100644 --- a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs +++ b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs @@ -5308,43 +5308,23 @@ internal Arm64() { } public static unsafe System.Numerics.Vector GatherVectorUInt16ZeroExtendFirstFaulting(System.Numerics.Vector mask, ushort* address, System.Numerics.Vector indices) { throw null; } public static System.Numerics.Vector GatherVectorUInt16ZeroExtendFirstFaulting(System.Numerics.Vector mask, System.Numerics.Vector addresses) { throw null; } public static unsafe System.Numerics.Vector GatherVectorUInt16ZeroExtendFirstFaulting(System.Numerics.Vector mask, ushort* address, System.Numerics.Vector indices) { throw null; } - public static unsafe System.Numerics.Vector GatherVectorUInt32WithByteOffsetsZeroExtend(System.Numerics.Vector mask, uint* address, System.Numerics.Vector offsets) { throw null; } - public static unsafe System.Numerics.Vector GatherVectorUInt32WithByteOffsetsZeroExtend(System.Numerics.Vector mask, uint* address, System.Numerics.Vector offsets) { throw null; } public static unsafe System.Numerics.Vector GatherVectorUInt32WithByteOffsetsZeroExtend(System.Numerics.Vector mask, uint* address, System.Numerics.Vector offsets) { throw null; } public static unsafe System.Numerics.Vector GatherVectorUInt32WithByteOffsetsZeroExtend(System.Numerics.Vector mask, uint* address, System.Numerics.Vector offsets) { throw null; } - public static unsafe System.Numerics.Vector GatherVectorUInt32WithByteOffsetsZeroExtend(System.Numerics.Vector mask, uint* address, System.Numerics.Vector offsets) { throw null; } - public static unsafe System.Numerics.Vector GatherVectorUInt32WithByteOffsetsZeroExtend(System.Numerics.Vector mask, uint* address, System.Numerics.Vector offsets) { throw null; } public static unsafe System.Numerics.Vector GatherVectorUInt32WithByteOffsetsZeroExtend(System.Numerics.Vector mask, uint* address, System.Numerics.Vector offsets) { throw null; } public static unsafe System.Numerics.Vector GatherVectorUInt32WithByteOffsetsZeroExtend(System.Numerics.Vector mask, uint* address, System.Numerics.Vector offsets) { throw null; } - public static unsafe System.Numerics.Vector GatherVectorUInt32WithByteOffsetsZeroExtendFirstFaulting(System.Numerics.Vector mask, uint* address, System.Numerics.Vector offsets) { throw null; } - public static unsafe System.Numerics.Vector GatherVectorUInt32WithByteOffsetsZeroExtendFirstFaulting(System.Numerics.Vector mask, uint* address, System.Numerics.Vector offsets) { throw null; } public static unsafe System.Numerics.Vector GatherVectorUInt32WithByteOffsetsZeroExtendFirstFaulting(System.Numerics.Vector mask, uint* address, System.Numerics.Vector offsets) { throw null; } public static unsafe System.Numerics.Vector GatherVectorUInt32WithByteOffsetsZeroExtendFirstFaulting(System.Numerics.Vector mask, uint* address, System.Numerics.Vector offsets) { throw null; } - public static unsafe System.Numerics.Vector GatherVectorUInt32WithByteOffsetsZeroExtendFirstFaulting(System.Numerics.Vector mask, uint* address, System.Numerics.Vector offsets) { throw null; } - public static unsafe System.Numerics.Vector GatherVectorUInt32WithByteOffsetsZeroExtendFirstFaulting(System.Numerics.Vector mask, uint* address, System.Numerics.Vector offsets) { throw null; } public static unsafe System.Numerics.Vector GatherVectorUInt32WithByteOffsetsZeroExtendFirstFaulting(System.Numerics.Vector mask, uint* address, System.Numerics.Vector offsets) { throw null; } public static unsafe System.Numerics.Vector GatherVectorUInt32WithByteOffsetsZeroExtendFirstFaulting(System.Numerics.Vector mask, uint* address, System.Numerics.Vector offsets) { throw null; } - public static unsafe System.Numerics.Vector GatherVectorUInt32ZeroExtend(System.Numerics.Vector mask, uint* address, System.Numerics.Vector indices) { throw null; } - // public static System.Numerics.Vector GatherVectorUInt32ZeroExtend(System.Numerics.Vector mask, System.Numerics.Vector addresses) { throw null; } - public static unsafe System.Numerics.Vector GatherVectorUInt32ZeroExtend(System.Numerics.Vector mask, uint* address, System.Numerics.Vector indices) { throw null; } public static unsafe System.Numerics.Vector GatherVectorUInt32ZeroExtend(System.Numerics.Vector mask, uint* address, System.Numerics.Vector indices) { throw null; } public static System.Numerics.Vector GatherVectorUInt32ZeroExtend(System.Numerics.Vector mask, System.Numerics.Vector addresses) { throw null; } public static unsafe System.Numerics.Vector GatherVectorUInt32ZeroExtend(System.Numerics.Vector mask, uint* address, System.Numerics.Vector indices) { throw null; } - public static unsafe System.Numerics.Vector GatherVectorUInt32ZeroExtend(System.Numerics.Vector mask, uint* address, System.Numerics.Vector indices) { throw null; } - // public static System.Numerics.Vector GatherVectorUInt32ZeroExtend(System.Numerics.Vector mask, System.Numerics.Vector addresses) { throw null; } - public static unsafe System.Numerics.Vector GatherVectorUInt32ZeroExtend(System.Numerics.Vector mask, uint* address, System.Numerics.Vector indices) { throw null; } public static unsafe System.Numerics.Vector GatherVectorUInt32ZeroExtend(System.Numerics.Vector mask, uint* address, System.Numerics.Vector indices) { throw null; } public static System.Numerics.Vector GatherVectorUInt32ZeroExtend(System.Numerics.Vector mask, System.Numerics.Vector addresses) { throw null; } public static unsafe System.Numerics.Vector GatherVectorUInt32ZeroExtend(System.Numerics.Vector mask, uint* address, System.Numerics.Vector indices) { throw null; } - public static unsafe System.Numerics.Vector GatherVectorUInt32ZeroExtendFirstFaulting(System.Numerics.Vector mask, uint* address, System.Numerics.Vector indices) { throw null; } - // public static System.Numerics.Vector GatherVectorUInt32ZeroExtendFirstFaulting(System.Numerics.Vector mask, System.Numerics.Vector addresses) { throw null; } - public static unsafe System.Numerics.Vector GatherVectorUInt32ZeroExtendFirstFaulting(System.Numerics.Vector mask, uint* address, System.Numerics.Vector indices) { throw null; } public static unsafe System.Numerics.Vector GatherVectorUInt32ZeroExtendFirstFaulting(System.Numerics.Vector mask, uint* address, System.Numerics.Vector indices) { throw null; } public static System.Numerics.Vector GatherVectorUInt32ZeroExtendFirstFaulting(System.Numerics.Vector mask, System.Numerics.Vector addresses) { throw null; } public static unsafe System.Numerics.Vector GatherVectorUInt32ZeroExtendFirstFaulting(System.Numerics.Vector mask, uint* address, System.Numerics.Vector indices) { throw null; } - public static unsafe System.Numerics.Vector GatherVectorUInt32ZeroExtendFirstFaulting(System.Numerics.Vector mask, uint* address, System.Numerics.Vector indices) { throw null; } - // public static System.Numerics.Vector GatherVectorUInt32ZeroExtendFirstFaulting(System.Numerics.Vector mask, System.Numerics.Vector addresses) { throw null; } - public static unsafe System.Numerics.Vector GatherVectorUInt32ZeroExtendFirstFaulting(System.Numerics.Vector mask, uint* address, System.Numerics.Vector indices) { throw null; } public static unsafe System.Numerics.Vector GatherVectorUInt32ZeroExtendFirstFaulting(System.Numerics.Vector mask, uint* address, System.Numerics.Vector indices) { throw null; } public static System.Numerics.Vector GatherVectorUInt32ZeroExtendFirstFaulting(System.Numerics.Vector mask, System.Numerics.Vector addresses) { throw null; } public static unsafe System.Numerics.Vector GatherVectorUInt32ZeroExtendFirstFaulting(System.Numerics.Vector mask, uint* address, System.Numerics.Vector indices) { throw null; } @@ -6412,6 +6392,95 @@ internal Arm64() { } public static System.Numerics.Vector FusedSubtractHalving(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static System.Numerics.Vector FusedSubtractHalving(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static System.Numerics.Vector FusedSubtractHalving(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + // public static System.Numerics.Vector GatherVectorByteZeroExtendNonTemporal(System.Numerics.Vector mask, System.Numerics.Vector addresses) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorByteZeroExtendNonTemporal(System.Numerics.Vector mask, byte* address, System.Numerics.Vector offsets) { throw null; } + public static System.Numerics.Vector GatherVectorByteZeroExtendNonTemporal(System.Numerics.Vector mask, System.Numerics.Vector addresses) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorByteZeroExtendNonTemporal(System.Numerics.Vector mask, byte* address, System.Numerics.Vector offsets) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorByteZeroExtendNonTemporal(System.Numerics.Vector mask, byte* address, System.Numerics.Vector offsets) { throw null; } + // public static System.Numerics.Vector GatherVectorByteZeroExtendNonTemporal(System.Numerics.Vector mask, System.Numerics.Vector addresses) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorByteZeroExtendNonTemporal(System.Numerics.Vector mask, byte* address, System.Numerics.Vector offsets) { throw null; } + public static System.Numerics.Vector GatherVectorByteZeroExtendNonTemporal(System.Numerics.Vector mask, System.Numerics.Vector addresses) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorByteZeroExtendNonTemporal(System.Numerics.Vector mask, byte* address, System.Numerics.Vector offsets) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorByteZeroExtendNonTemporal(System.Numerics.Vector mask, byte* address, System.Numerics.Vector offsets) { throw null; } + // public static System.Numerics.Vector GatherVectorInt16SignExtendNonTemporal(System.Numerics.Vector mask, System.Numerics.Vector addresses) { throw null; } + public static System.Numerics.Vector GatherVectorInt16SignExtendNonTemporal(System.Numerics.Vector mask, System.Numerics.Vector addresses) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorInt16SignExtendNonTemporal(System.Numerics.Vector mask, short* address, System.Numerics.Vector indices) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorInt16SignExtendNonTemporal(System.Numerics.Vector mask, short* address, System.Numerics.Vector indices) { throw null; } + // public static System.Numerics.Vector GatherVectorInt16SignExtendNonTemporal(System.Numerics.Vector mask, System.Numerics.Vector addresses) { throw null; } + public static System.Numerics.Vector GatherVectorInt16SignExtendNonTemporal(System.Numerics.Vector mask, System.Numerics.Vector addresses) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorInt16SignExtendNonTemporal(System.Numerics.Vector mask, short* address, System.Numerics.Vector indices) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorInt16SignExtendNonTemporal(System.Numerics.Vector mask, short* address, System.Numerics.Vector indices) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorInt16WithByteOffsetsSignExtendNonTemporal(System.Numerics.Vector mask, short* address, System.Numerics.Vector offsets) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorInt16WithByteOffsetsSignExtendNonTemporal(System.Numerics.Vector mask, short* address, System.Numerics.Vector offsets) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorInt16WithByteOffsetsSignExtendNonTemporal(System.Numerics.Vector mask, short* address, System.Numerics.Vector offsets) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorInt16WithByteOffsetsSignExtendNonTemporal(System.Numerics.Vector mask, short* address, System.Numerics.Vector offsets) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorInt16WithByteOffsetsSignExtendNonTemporal(System.Numerics.Vector mask, short* address, System.Numerics.Vector offsets) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorInt16WithByteOffsetsSignExtendNonTemporal(System.Numerics.Vector mask, short* address, System.Numerics.Vector offsets) { throw null; } + public static System.Numerics.Vector GatherVectorInt32SignExtendNonTemporal(System.Numerics.Vector mask, System.Numerics.Vector addresses) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorInt32SignExtendNonTemporal(System.Numerics.Vector mask, int* address, System.Numerics.Vector indices) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorInt32SignExtendNonTemporal(System.Numerics.Vector mask, int* address, System.Numerics.Vector indices) { throw null; } + public static System.Numerics.Vector GatherVectorInt32SignExtendNonTemporal(System.Numerics.Vector mask, System.Numerics.Vector addresses) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorInt32SignExtendNonTemporal(System.Numerics.Vector mask, int* address, System.Numerics.Vector indices) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorInt32SignExtendNonTemporal(System.Numerics.Vector mask, int* address, System.Numerics.Vector indices) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorInt32WithByteOffsetsSignExtendNonTemporal(System.Numerics.Vector mask, int* address, System.Numerics.Vector offsets) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorInt32WithByteOffsetsSignExtendNonTemporal(System.Numerics.Vector mask, int* address, System.Numerics.Vector offsets) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorInt32WithByteOffsetsSignExtendNonTemporal(System.Numerics.Vector mask, int* address, System.Numerics.Vector offsets) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorInt32WithByteOffsetsSignExtendNonTemporal(System.Numerics.Vector mask, int* address, System.Numerics.Vector offsets) { throw null; } + public static System.Numerics.Vector GatherVectorNonTemporal(System.Numerics.Vector mask, System.Numerics.Vector addresses) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorNonTemporal(System.Numerics.Vector mask, double* address, System.Numerics.Vector indices) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorNonTemporal(System.Numerics.Vector mask, double* address, System.Numerics.Vector indices) { throw null; } + // public static System.Numerics.Vector GatherVectorNonTemporal(System.Numerics.Vector mask, System.Numerics.Vector addresses) { throw null; } + public static System.Numerics.Vector GatherVectorNonTemporal(System.Numerics.Vector mask, System.Numerics.Vector addresses) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorNonTemporal(System.Numerics.Vector mask, long* address, System.Numerics.Vector indices) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorNonTemporal(System.Numerics.Vector mask, long* address, System.Numerics.Vector indices) { throw null; } + // public static System.Numerics.Vector GatherVectorNonTemporal(System.Numerics.Vector mask, System.Numerics.Vector addresses) { throw null; } + // public static System.Numerics.Vector GatherVectorNonTemporal(System.Numerics.Vector mask, System.Numerics.Vector addresses) { throw null; } + public static System.Numerics.Vector GatherVectorNonTemporal(System.Numerics.Vector mask, System.Numerics.Vector addresses) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorNonTemporal(System.Numerics.Vector mask, ulong* address, System.Numerics.Vector indices) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorNonTemporal(System.Numerics.Vector mask, ulong* address, System.Numerics.Vector indices) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorWithByteOffsetsNonTemporal(System.Numerics.Vector mask, double* address, System.Numerics.Vector offsets) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorWithByteOffsetsNonTemporal(System.Numerics.Vector mask, double* address, System.Numerics.Vector offsets) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorWithByteOffsetsNonTemporal(System.Numerics.Vector mask, int* address, System.Numerics.Vector offsets) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorWithByteOffsetsNonTemporal(System.Numerics.Vector mask, long* address, System.Numerics.Vector offsets) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorWithByteOffsetsNonTemporal(System.Numerics.Vector mask, long* address, System.Numerics.Vector offsets) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorWithByteOffsetsNonTemporal(System.Numerics.Vector mask, float* address, System.Numerics.Vector offsets) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorWithByteOffsetsNonTemporal(System.Numerics.Vector mask, uint* address, System.Numerics.Vector offsets) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorWithByteOffsetsNonTemporal(System.Numerics.Vector mask, ulong* address, System.Numerics.Vector offsets) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorWithByteOffsetsNonTemporal(System.Numerics.Vector mask, ulong* address, System.Numerics.Vector offsets) { throw null; } + // public static System.Numerics.Vector GatherVectorSByteSignExtendNonTemporal(System.Numerics.Vector mask, System.Numerics.Vector addresses) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorSByteSignExtendNonTemporal(System.Numerics.Vector mask, sbyte* address, System.Numerics.Vector offsets) { throw null; } + public static System.Numerics.Vector GatherVectorSByteSignExtendNonTemporal(System.Numerics.Vector mask, System.Numerics.Vector addresses) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorSByteSignExtendNonTemporal(System.Numerics.Vector mask, sbyte* address, System.Numerics.Vector offsets) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorSByteSignExtendNonTemporal(System.Numerics.Vector mask, sbyte* address, System.Numerics.Vector offsets) { throw null; } + // public static System.Numerics.Vector GatherVectorSByteSignExtendNonTemporal(System.Numerics.Vector mask, System.Numerics.Vector addresses) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorSByteSignExtendNonTemporal(System.Numerics.Vector mask, sbyte* address, System.Numerics.Vector offsets) { throw null; } + public static System.Numerics.Vector GatherVectorSByteSignExtendNonTemporal(System.Numerics.Vector mask, System.Numerics.Vector addresses) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorSByteSignExtendNonTemporal(System.Numerics.Vector mask, sbyte* address, System.Numerics.Vector offsets) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorSByteSignExtendNonTemporal(System.Numerics.Vector mask, sbyte* address, System.Numerics.Vector offsets) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorUInt16WithByteOffsetsZeroExtendNonTemporal(System.Numerics.Vector mask, ushort* address, System.Numerics.Vector offsets) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorUInt16WithByteOffsetsZeroExtendNonTemporal(System.Numerics.Vector mask, ushort* address, System.Numerics.Vector offsets) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorUInt16WithByteOffsetsZeroExtendNonTemporal(System.Numerics.Vector mask, ushort* address, System.Numerics.Vector offsets) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorUInt16WithByteOffsetsZeroExtendNonTemporal(System.Numerics.Vector mask, ushort* address, System.Numerics.Vector offsets) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorUInt16WithByteOffsetsZeroExtendNonTemporal(System.Numerics.Vector mask, ushort* address, System.Numerics.Vector offsets) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorUInt16WithByteOffsetsZeroExtendNonTemporal(System.Numerics.Vector mask, ushort* address, System.Numerics.Vector offsets) { throw null; } + // public static System.Numerics.Vector GatherVectorUInt16ZeroExtendNonTemporal(System.Numerics.Vector mask, System.Numerics.Vector addresses) { throw null; } + public static System.Numerics.Vector GatherVectorUInt16ZeroExtendNonTemporal(System.Numerics.Vector mask, System.Numerics.Vector addresses) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorUInt16ZeroExtendNonTemporal(System.Numerics.Vector mask, ushort* address, System.Numerics.Vector indices) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorUInt16ZeroExtendNonTemporal(System.Numerics.Vector mask, ushort* address, System.Numerics.Vector indices) { throw null; } + // public static System.Numerics.Vector GatherVectorUInt16ZeroExtendNonTemporal(System.Numerics.Vector mask, System.Numerics.Vector addresses) { throw null; } + public static System.Numerics.Vector GatherVectorUInt16ZeroExtendNonTemporal(System.Numerics.Vector mask, System.Numerics.Vector addresses) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorUInt16ZeroExtendNonTemporal(System.Numerics.Vector mask, ushort* address, System.Numerics.Vector indices) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorUInt16ZeroExtendNonTemporal(System.Numerics.Vector mask, ushort* address, System.Numerics.Vector indices) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorUInt32WithByteOffsetsZeroExtendNonTemporal(System.Numerics.Vector mask, uint* address, System.Numerics.Vector offsets) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorUInt32WithByteOffsetsZeroExtendNonTemporal(System.Numerics.Vector mask, uint* address, System.Numerics.Vector offsets) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorUInt32WithByteOffsetsZeroExtendNonTemporal(System.Numerics.Vector mask, uint* address, System.Numerics.Vector offsets) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorUInt32WithByteOffsetsZeroExtendNonTemporal(System.Numerics.Vector mask, uint* address, System.Numerics.Vector offsets) { throw null; } + public static System.Numerics.Vector GatherVectorUInt32ZeroExtendNonTemporal(System.Numerics.Vector mask, System.Numerics.Vector addresses) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorUInt32ZeroExtendNonTemporal(System.Numerics.Vector mask, uint* address, System.Numerics.Vector indices) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorUInt32ZeroExtendNonTemporal(System.Numerics.Vector mask, uint* address, System.Numerics.Vector indices) { throw null; } + public static System.Numerics.Vector GatherVectorUInt32ZeroExtendNonTemporal(System.Numerics.Vector mask, System.Numerics.Vector addresses) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorUInt32ZeroExtendNonTemporal(System.Numerics.Vector mask, uint* address, System.Numerics.Vector indices) { throw null; } + public static unsafe System.Numerics.Vector GatherVectorUInt32ZeroExtendNonTemporal(System.Numerics.Vector mask, uint* address, System.Numerics.Vector indices) { throw null; } public static System.Numerics.Vector InterleavingXorEvenOdd(System.Numerics.Vector odd, System.Numerics.Vector leftEven, System.Numerics.Vector rightOdd) { throw null; } public static System.Numerics.Vector InterleavingXorEvenOdd(System.Numerics.Vector odd, System.Numerics.Vector leftEven, System.Numerics.Vector rightOdd) { throw null; } public static System.Numerics.Vector InterleavingXorEvenOdd(System.Numerics.Vector odd, System.Numerics.Vector leftEven, System.Numerics.Vector rightOdd) { throw null; } diff --git a/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/Directory/Delete_MountVolume.cs b/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/Directory/Delete_MountVolume.cs index f4b153d94d9326..ed74831de984f6 100644 --- a/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/Directory/Delete_MountVolume.cs +++ b/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/Directory/Delete_MountVolume.cs @@ -79,8 +79,11 @@ public static void RunTest() } finally { - MountHelper.Unmount(mountedDirName); - DeleteDir(mountedDirName, true); + if (Directory.Exists(mountedDirName)) + { + MountHelper.Unmount(mountedDirName); + DeleteDir(mountedDirName, true); + } } File.AppendAllText(debugFileName, string.Format("Completed scenario {0}", Environment.NewLine)); } @@ -124,8 +127,11 @@ public static void RunTest() } finally { - MountHelper.Unmount(mountedDirName); - DeleteDir(mountedDirName, true); + if (Directory.Exists(mountedDirName)) + { + MountHelper.Unmount(mountedDirName); + DeleteDir(mountedDirName, true); + } } File.AppendAllText(debugFileName, string.Format("Completed scenario {0}", Environment.NewLine)); } @@ -166,8 +172,11 @@ public static void RunTest() } finally { - MountHelper.Unmount(mountedDirName); - DeleteDir(mountedDirName, true); + if (Directory.Exists(mountedDirName)) + { + MountHelper.Unmount(mountedDirName); + DeleteDir(mountedDirName, true); + } } File.AppendAllText(debugFileName, string.Format("Completed scenario {0}", Environment.NewLine)); } @@ -208,8 +217,11 @@ public static void RunTest() } finally { - MountHelper.Unmount(mountedDirName); - DeleteDir(mountedDirName, true); + if (Directory.Exists(mountedDirName)) + { + MountHelper.Unmount(mountedDirName); + DeleteDir(mountedDirName, true); + } } File.AppendAllText(debugFileName, string.Format("Completed scenario {0}", Environment.NewLine)); } diff --git a/src/libraries/System.Security.Cryptography.Pkcs/src/System.Security.Cryptography.Pkcs.csproj b/src/libraries/System.Security.Cryptography.Pkcs/src/System.Security.Cryptography.Pkcs.csproj index 59e67ad0997f38..19cc655555f692 100644 --- a/src/libraries/System.Security.Cryptography.Pkcs/src/System.Security.Cryptography.Pkcs.csproj +++ b/src/libraries/System.Security.Cryptography.Pkcs/src/System.Security.Cryptography.Pkcs.csproj @@ -25,7 +25,7 @@ System.Security.Cryptography.Pkcs.EnvelopedCms - + diff --git a/src/libraries/System.Security.Cryptography/src/System.Security.Cryptography.csproj b/src/libraries/System.Security.Cryptography/src/System.Security.Cryptography.csproj index 2a7ddd85d7f045..c0df094935c129 100644 --- a/src/libraries/System.Security.Cryptography/src/System.Security.Cryptography.csproj +++ b/src/libraries/System.Security.Cryptography/src/System.Security.Cryptography.csproj @@ -22,7 +22,7 @@ - + true - + Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml diff --git a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs index 329a369b4a0135..a865466d5f40b8 100644 --- a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs +++ b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs @@ -47,7 +47,7 @@ private sealed class Parser private readonly Dictionary _generatedTypes = new(SymbolEqualityComparer.Default); #pragma warning restore - public List Diagnostics { get; } = new(); + public List Diagnostics { get; } = new(); private Location? _contextClassLocation; public void ReportDiagnostic(DiagnosticDescriptor descriptor, Location? location, params object?[]? messageArgs) @@ -60,7 +60,7 @@ public void ReportDiagnostic(DiagnosticDescriptor descriptor, Location? location location = _contextClassLocation; } - Diagnostics.Add(DiagnosticInfo.Create(descriptor, location, messageArgs)); + Diagnostics.Add(Diagnostic.Create(descriptor, location, messageArgs)); } public Parser(KnownTypeSymbols knownSymbols) diff --git a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Roslyn3.11.cs b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Roslyn3.11.cs index 965bf7fc210751..5397715ede9da8 100644 --- a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Roslyn3.11.cs +++ b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Roslyn3.11.cs @@ -75,9 +75,9 @@ public void Execute(GeneratorExecutionContext executionContext) } // Stage 2. Report any diagnostics gathered by the parser. - foreach (DiagnosticInfo diagnosticInfo in parser.Diagnostics) + foreach (Diagnostic diagnostic in parser.Diagnostics) { - executionContext.ReportDiagnostic(diagnosticInfo.CreateDiagnostic()); + executionContext.ReportDiagnostic(diagnostic); } if (contextGenerationSpecs is null) diff --git a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Roslyn4.0.cs b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Roslyn4.0.cs index 75f1f51269e7a6..79fab10a1cfc34 100644 --- a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Roslyn4.0.cs +++ b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Roslyn4.0.cs @@ -10,7 +10,6 @@ #if !ROSLYN4_4_OR_GREATER using Microsoft.CodeAnalysis.DotnetRuntime.Extensions; #endif -using SourceGenerators; namespace System.Text.Json.SourceGeneration { @@ -32,7 +31,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) IncrementalValueProvider knownTypeSymbols = context.CompilationProvider .Select((compilation, _) => new KnownTypeSymbols(compilation)); - IncrementalValuesProvider<(ContextGenerationSpec?, ImmutableEquatableArray)> contextGenerationSpecs = context.SyntaxProvider + IncrementalValuesProvider<(ContextGenerationSpec?, ImmutableArray)> contextGenerationSpecs = context.SyntaxProvider .ForAttributeWithMetadataName( #if !ROSLYN4_4_OR_GREATER context, @@ -54,7 +53,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) #pragma warning restore RS1035 Parser parser = new(tuple.Right); ContextGenerationSpec? contextGenerationSpec = parser.ParseContextGenerationSpec(tuple.Left.ContextClass, tuple.Left.SemanticModel, cancellationToken); - ImmutableEquatableArray diagnostics = parser.Diagnostics.ToImmutableEquatableArray(); + ImmutableArray diagnostics = parser.Diagnostics.ToImmutableArray(); return (contextGenerationSpec, diagnostics); #pragma warning disable RS1035 } @@ -69,23 +68,36 @@ public void Initialize(IncrementalGeneratorInitializationContext context) #endif ; - context.RegisterSourceOutput(contextGenerationSpecs, ReportDiagnosticsAndEmitSource); + // Project the combined pipeline result to just the equatable model, discarding diagnostics. + // ContextGenerationSpec implements value equality, so Roslyn's Select operator will compare + // successive model snapshots and only propagate changes downstream when the model structurally + // differs. This ensures source generation is fully incremental: re-emitting code only when + // the serialization spec actually changes, not on every keystroke or positional shift. + IncrementalValuesProvider sourceGenerationSpecs = + contextGenerationSpecs.Select(static (t, _) => t.Item1); + + context.RegisterSourceOutput(sourceGenerationSpecs, EmitSource); + + // Project to just the diagnostics, discarding the model. ImmutableArray does not + // implement value equality, so Roslyn's incremental pipeline uses reference equality for these + // values — the callback fires on every compilation change. This is by design: diagnostic + // emission is cheap, and we need fresh SourceLocation instances that are pragma-suppressible + // (cf. https://github.com/dotnet/runtime/issues/92509). + // No source code is generated from this pipeline — it exists solely to report diagnostics. + IncrementalValuesProvider> diagnostics = + contextGenerationSpecs.Select(static (t, _) => t.Item2); + + context.RegisterSourceOutput(diagnostics, EmitDiagnostics); } - private void ReportDiagnosticsAndEmitSource(SourceProductionContext sourceProductionContext, (ContextGenerationSpec? ContextGenerationSpec, ImmutableEquatableArray Diagnostics) input) + private void EmitSource(SourceProductionContext sourceProductionContext, ContextGenerationSpec? contextGenerationSpec) { - // Report any diagnostics ahead of emitting. - foreach (DiagnosticInfo diagnostic in input.Diagnostics) - { - sourceProductionContext.ReportDiagnostic(diagnostic.CreateDiagnostic()); - } - - if (input.ContextGenerationSpec is null) + if (contextGenerationSpec is null) { return; } - OnSourceEmitting?.Invoke(ImmutableArray.Create(input.ContextGenerationSpec)); + OnSourceEmitting?.Invoke(ImmutableArray.Create(contextGenerationSpec)); // Ensure the source generator emits number literals using invariant culture. // This prevents issues such as locale-specific negative signs (e.g., U+2212 in fi-FI) @@ -96,7 +108,7 @@ private void ReportDiagnosticsAndEmitSource(SourceProductionContext sourceProduc try { Emitter emitter = new(sourceProductionContext); - emitter.Emit(input.ContextGenerationSpec); + emitter.Emit(contextGenerationSpec); } finally { @@ -105,6 +117,14 @@ private void ReportDiagnosticsAndEmitSource(SourceProductionContext sourceProduc #pragma warning restore RS1035 } + private static void EmitDiagnostics(SourceProductionContext context, ImmutableArray diagnostics) + { + foreach (Diagnostic diagnostic in diagnostics) + { + context.ReportDiagnostic(diagnostic); + } + } + /// /// Instrumentation helper for unit tests. /// diff --git a/src/libraries/System.Text.Json/gen/System.Text.Json.SourceGeneration.targets b/src/libraries/System.Text.Json/gen/System.Text.Json.SourceGeneration.targets index aa7ae500ce7870..2d4351a3eab530 100644 --- a/src/libraries/System.Text.Json/gen/System.Text.Json.SourceGeneration.targets +++ b/src/libraries/System.Text.Json/gen/System.Text.Json.SourceGeneration.targets @@ -31,7 +31,6 @@ - diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorDiagnosticsTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorDiagnosticsTests.cs index b8e3073a857cf5..5712a52072a110 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorDiagnosticsTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorDiagnosticsTests.cs @@ -5,6 +5,7 @@ using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Diagnostics; using Xunit; namespace System.Text.Json.SourceGeneration.UnitTests @@ -755,5 +756,33 @@ public partial class MyContext : JsonSerializerContext CompilationHelper.AssertEqualDiagnosticMessages(expectedDiagnostics, result.Diagnostics); } #endif + + [Fact] + public void Diagnostic_HasPragmaSuppressibleLocation() + { + // SYSLIB1038: JsonInclude attribute on inaccessible member (Warning, configurable). + string source = """ + #pragma warning disable SYSLIB1038 + using System.Text.Json.Serialization; + + namespace Test + { + public class MyClass + { + [JsonInclude] + private int PrivateField; + } + + [JsonSerializable(typeof(MyClass))] + public partial class JsonContext : JsonSerializerContext { } + } + """; + + Compilation compilation = CompilationHelper.CreateCompilation(source); + JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation, disableDiagnosticValidation: true); + var effective = CompilationWithAnalyzers.GetEffectiveDiagnostics(result.Diagnostics, compilation); + Diagnostic diagnostic = Assert.Single(effective, d => d.Id == "SYSLIB1038"); + Assert.True(diagnostic.IsSuppressed); + } } } diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorIncrementalTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorIncrementalTests.cs index d08c07c2e741ea..7be4413b44befa 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorIncrementalTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorIncrementalTests.cs @@ -145,7 +145,6 @@ public static void SourceGenModelDoesNotEncapsulateSymbolsOrCompilationData(Func { JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(factory(), disableDiagnosticValidation: true); WalkObjectGraph(result.ContextGenerationSpecs); - WalkObjectGraph(result.Diagnostics); static void WalkObjectGraph(object obj) { diff --git a/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Parser.cs b/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Parser.cs index 947d0bc0b049b5..1d1df92c107d9b 100644 --- a/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Parser.cs +++ b/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Parser.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Immutable; @@ -20,7 +20,7 @@ public partial class RegexGenerator private const string GeneratedRegexAttributeName = "System.Text.RegularExpressions.GeneratedRegexAttribute"; /// - /// Returns null if nothing to do, if there's an error to report, + /// Returns null if nothing to do, a if there's an error to report, /// or if the type was analyzed successfully. /// private static object? GetRegexMethodDataOrFailureDiagnostic( @@ -32,7 +32,7 @@ public partial class RegexGenerator // of being able to flag invalid use when [GeneratedRegex] is applied incorrectly. // Otherwise, if the ForAttributeWithMetadataName call excluded these, [GeneratedRegex] // could be applied to them and we wouldn't be able to issue a diagnostic. - return new DiagnosticData(DiagnosticDescriptors.RegexMemberMustHaveValidSignature, GetComparableLocation(context.TargetNode)); + return Diagnostic.Create(DiagnosticDescriptors.RegexMemberMustHaveValidSignature, context.TargetNode.GetLocation()); } var memberSyntax = (MemberDeclarationSyntax)context.TargetNode; @@ -62,19 +62,19 @@ public partial class RegexGenerator ImmutableArray boundAttributes = context.Attributes; if (boundAttributes.Length != 1) { - return new DiagnosticData(DiagnosticDescriptors.MultipleGeneratedRegexAttributes, GetComparableLocation(memberSyntax)); + return Diagnostic.Create(DiagnosticDescriptors.MultipleGeneratedRegexAttributes, memberSyntax.GetLocation()); } AttributeData generatedRegexAttr = boundAttributes[0]; if (generatedRegexAttr.ConstructorArguments.Any(ca => ca.Kind == TypedConstantKind.Error)) { - return new DiagnosticData(DiagnosticDescriptors.InvalidGeneratedRegexAttribute, GetComparableLocation(memberSyntax)); + return Diagnostic.Create(DiagnosticDescriptors.InvalidGeneratedRegexAttribute, memberSyntax.GetLocation()); } ImmutableArray items = generatedRegexAttr.ConstructorArguments; if (items.Length is 0 or > 4) { - return new DiagnosticData(DiagnosticDescriptors.InvalidGeneratedRegexAttribute, GetComparableLocation(memberSyntax)); + return Diagnostic.Create(DiagnosticDescriptors.InvalidGeneratedRegexAttribute, memberSyntax.GetLocation()); } string? pattern = items[0].Value as string; @@ -106,7 +106,7 @@ public partial class RegexGenerator if (pattern is null || cultureName is null) { - return new DiagnosticData(DiagnosticDescriptors.InvalidRegexArguments, GetComparableLocation(memberSyntax), "(null)"); + return Diagnostic.Create(DiagnosticDescriptors.InvalidRegexArguments, memberSyntax.GetLocation(), "(null)"); } bool nullableRegex; @@ -118,7 +118,7 @@ public partial class RegexGenerator regexMethodSymbol.Arity != 0 || !SymbolEqualityComparer.Default.Equals(regexMethodSymbol.ReturnType, regexSymbol)) { - return new DiagnosticData(DiagnosticDescriptors.RegexMemberMustHaveValidSignature, GetComparableLocation(memberSyntax)); + return Diagnostic.Create(DiagnosticDescriptors.RegexMemberMustHaveValidSignature, memberSyntax.GetLocation()); } nullableRegex = regexMethodSymbol.ReturnNullableAnnotation == NullableAnnotation.Annotated; @@ -132,7 +132,7 @@ public partial class RegexGenerator regexPropertySymbol.SetMethod is not null || !SymbolEqualityComparer.Default.Equals(regexPropertySymbol.Type, regexSymbol)) { - return new DiagnosticData(DiagnosticDescriptors.RegexMemberMustHaveValidSignature, GetComparableLocation(memberSyntax)); + return Diagnostic.Create(DiagnosticDescriptors.RegexMemberMustHaveValidSignature, memberSyntax.GetLocation()); } nullableRegex = regexPropertySymbol.NullableAnnotation == NullableAnnotation.Annotated; @@ -154,7 +154,7 @@ regexPropertySymbol.SetMethod is not null || } catch (Exception e) { - return new DiagnosticData(DiagnosticDescriptors.InvalidRegexArguments, GetComparableLocation(memberSyntax), e.Message); + return Diagnostic.Create(DiagnosticDescriptors.InvalidRegexArguments, memberSyntax.GetLocation(), e.Message); } if ((regexOptionsWithPatternOptions & RegexOptions.IgnoreCase) != 0 && !string.IsNullOrEmpty(cultureName)) @@ -162,7 +162,7 @@ regexPropertySymbol.SetMethod is not null || if ((regexOptions & RegexOptions.CultureInvariant) != 0) { // User passed in both a culture name and set RegexOptions.CultureInvariant which causes an explicit conflict. - return new DiagnosticData(DiagnosticDescriptors.InvalidRegexArguments, GetComparableLocation(memberSyntax), "cultureName"); + return Diagnostic.Create(DiagnosticDescriptors.InvalidRegexArguments, memberSyntax.GetLocation(), "cultureName"); } try @@ -171,7 +171,7 @@ regexPropertySymbol.SetMethod is not null || } catch (CultureNotFoundException) { - return new DiagnosticData(DiagnosticDescriptors.InvalidRegexArguments, GetComparableLocation(memberSyntax), "cultureName"); + return Diagnostic.Create(DiagnosticDescriptors.InvalidRegexArguments, memberSyntax.GetLocation(), "cultureName"); } } @@ -189,13 +189,13 @@ regexPropertySymbol.SetMethod is not null || RegexOptions.Singleline; if ((regexOptions & ~SupportedOptions) != 0) { - return new DiagnosticData(DiagnosticDescriptors.InvalidRegexArguments, GetComparableLocation(memberSyntax), "options"); + return Diagnostic.Create(DiagnosticDescriptors.InvalidRegexArguments, memberSyntax.GetLocation(), "options"); } // Validate the timeout if (matchTimeout is 0 or < -1) { - return new DiagnosticData(DiagnosticDescriptors.InvalidRegexArguments, GetComparableLocation(memberSyntax), "matchTimeout"); + return Diagnostic.Create(DiagnosticDescriptors.InvalidRegexArguments, memberSyntax.GetLocation(), "matchTimeout"); } // Determine the namespace the class is declared in, if any @@ -214,7 +214,7 @@ regexPropertySymbol.SetMethod is not null || var result = new RegexPatternAndSyntax( regexType, IsProperty: regexMemberSymbol is IPropertySymbol, - GetComparableLocation(memberSyntax), + memberSyntax.GetLocation(), regexMemberSymbol.Name, memberSyntax.Modifiers.ToString(), nullableRegex, @@ -246,21 +246,13 @@ SyntaxKind.StructDeclaration or SyntaxKind.RecordDeclaration or SyntaxKind.RecordStructDeclaration or SyntaxKind.InterfaceDeclaration; - - // Get a Location object that doesn't store a reference to the compilation. - // That allows it to compare equally across compilations. - static Location GetComparableLocation(SyntaxNode syntax) - { - var location = syntax.GetLocation(); - return Location.Create(location.SourceTree?.FilePath ?? string.Empty, location.SourceSpan, location.GetLineSpan().Span); - } } /// Data about a regex directly from the GeneratedRegex attribute. internal sealed record RegexPatternAndSyntax(RegexType DeclaringType, bool IsProperty, Location DiagnosticLocation, string MemberName, string Modifiers, bool NullableRegex, string Pattern, RegexOptions Options, int? MatchTimeout, CultureInfo Culture, CompilationData CompilationData); /// Data about a regex, including a fully parsed RegexTree and subsequent analysis. - internal sealed record RegexMethod(RegexType DeclaringType, bool IsProperty, Location DiagnosticLocation, string MemberName, string Modifiers, bool NullableRegex, string Pattern, RegexOptions Options, int? MatchTimeout, RegexTree Tree, AnalysisResults Analysis, CompilationData CompilationData) + internal sealed record RegexMethod(RegexType DeclaringType, bool IsProperty, string MemberName, string Modifiers, bool NullableRegex, string Pattern, RegexOptions Options, int? MatchTimeout, RegexTree Tree, AnalysisResults Analysis, CompilationData CompilationData) { public string? GeneratedName { get; set; } public bool IsDuplicate { get; set; } diff --git a/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.cs b/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.cs index 98e3f1ac35c036..69174c2a508efd 100644 --- a/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.cs +++ b/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.cs @@ -45,10 +45,13 @@ internal record struct CompilationData(bool AllowUnsafe, bool CheckOverflow, Lan public void Initialize(IncrementalGeneratorInitializationContext context) { // Produces one entry per generated regex. This may be: - // - DiagnosticData in the case of a failure that should end the compilation + // - Diagnostic in the case of a failure that should end the compilation // - (RegexMethod regexMethod, string runnerFactoryImplementation, Dictionary requiredHelpers) in the case of valid regex - // - (RegexMethod regexMethod, string reason, DiagnosticData diagnostic) in the case of a limited-support regex - IncrementalValueProvider> results = + // - (RegexMethod regexMethod, string reason, Diagnostic diagnostic) in the case of a limited-support regex + // + // Location is threaded separately from the records so that it doesn't participate in + // record equality — this allows the incremental pipeline to cache results by value. + IncrementalValueProvider<(ImmutableArray Results, ImmutableArray Diagnostics)> collected = context.SyntaxProvider // Find all MethodDeclarationSyntax nodes attributed with GeneratedRegex and gather the required information. @@ -67,8 +70,10 @@ public void Initialize(IncrementalGeneratorInitializationContext context) // Filter out any parsing errors that resulted in null objects being returned. .Where(static m => m is not null) - // The input here will either be a DiagnosticData (in the case of something erroneous detected in GetRegexMethodDataOrFailureDiagnostic) + // The input here will either be a Diagnostic (in the case of something erroneous detected in GetRegexMethodDataOrFailureDiagnostic) // or it will be a RegexPatternAndSyntax containing all of the successfully parsed data from the attribute/method. + // This step parses the regex tree and checks whether full code generation is supported. + // The DiagnosticLocation is consumed here for diagnostic creation and not propagated further. .Select((methodOrDiagnostic, _) => { if (methodOrDiagnostic is RegexPatternAndSyntax method) @@ -77,11 +82,20 @@ public void Initialize(IncrementalGeneratorInitializationContext context) { RegexTree regexTree = RegexParser.Parse(method.Pattern, method.Options | RegexOptions.Compiled, method.Culture); // make sure Compiled is included to get all optimizations applied to it AnalysisResults analysis = RegexTreeAnalyzer.Analyze(regexTree); - return new RegexMethod(method.DeclaringType, method.IsProperty, method.DiagnosticLocation, method.MemberName, method.Modifiers, method.NullableRegex, method.Pattern, method.Options, method.MatchTimeout, regexTree, analysis, method.CompilationData); + RegexMethod regexMethod = new(method.DeclaringType, method.IsProperty, method.MemberName, method.Modifiers, method.NullableRegex, method.Pattern, method.Options, method.MatchTimeout, regexTree, analysis, method.CompilationData); + + // If we're unable to generate a full implementation for this regex, report a diagnostic. + // We'll still output a limited implementation that just caches a new Regex(...). + if (!SupportsCodeGeneration(regexMethod, regexMethod.CompilationData.LanguageVersion, out string? reason)) + { + return (object)(regexMethod, reason, Diagnostic.Create(DiagnosticDescriptors.LimitedSourceGeneration, method.DiagnosticLocation), regexMethod.CompilationData); + } + + return regexMethod; } catch (Exception e) { - return new DiagnosticData(DiagnosticDescriptors.InvalidRegexArguments, method.DiagnosticLocation, e.Message); + return Diagnostic.Create(DiagnosticDescriptors.InvalidRegexArguments, method.DiagnosticLocation, e.Message); } } @@ -93,17 +107,10 @@ public void Initialize(IncrementalGeneratorInitializationContext context) { if (state is not RegexMethod regexMethod) { - Debug.Assert(state is DiagnosticData); + Debug.Assert(state is Diagnostic or ValueTuple); return state; } - // If we're unable to generate a full implementation for this regex, report a diagnostic. - // We'll still output a limited implementation that just caches a new Regex(...). - if (!SupportsCodeGeneration(regexMethod, regexMethod.CompilationData.LanguageVersion, out string? reason)) - { - return (regexMethod, reason, new DiagnosticData(DiagnosticDescriptors.LimitedSourceGeneration, regexMethod.DiagnosticLocation), regexMethod.CompilationData); - } - // Generate the core logic for the regex. Dictionary requiredHelpers = new(); var sw = new StringWriter(); @@ -115,30 +122,47 @@ public void Initialize(IncrementalGeneratorInitializationContext context) return (regexMethod, sw.ToString(), requiredHelpers, regexMethod.CompilationData); }) - // Combine all of the generated text outputs into a single batch. We then generate a single source output from that batch. + // Combine all of the generated text outputs into a single batch, then split + // the source model from diagnostics so they can be emitted independently. .Collect() - - // Apply sequence equality comparison on the result array for incremental caching. - .WithComparer(new ObjectImmutableArraySequenceEqualityComparer()); - - // When there something to output, take all the generated strings and concatenate them to output, - // and raise all of the created diagnostics. - context.RegisterSourceOutput(results, static (context, results) => - { - // Report any top-level diagnostics. - bool allFailures = true; - foreach (object result in results) + .Select(static (results, _) => { - if (result is DiagnosticData d) - { - context.ReportDiagnostic(d.ToDiagnostic()); - } - else + ImmutableArray.Builder? diagnostics = null; + ImmutableArray.Builder? filteredResults = null; + + foreach (object result in results) { - allFailures = false; + if (result is Diagnostic d) + { + (diagnostics ??= ImmutableArray.CreateBuilder()).Add(d); + } + else if (result is ValueTuple limitedSupportResult) + { + (diagnostics ??= ImmutableArray.CreateBuilder()).Add(limitedSupportResult.Item3); + (filteredResults ??= ImmutableArray.CreateBuilder()).Add( + (limitedSupportResult.Item1, limitedSupportResult.Item2, limitedSupportResult.Item4)); + } + else + { + (filteredResults ??= ImmutableArray.CreateBuilder()).Add(result); + } } - } - if (allFailures) + + return ( + Results: filteredResults?.ToImmutable() ?? ImmutableArray.Empty, + Diagnostics: diagnostics?.ToImmutable() ?? ImmutableArray.Empty); + }); + + // Project to just the source model, discarding diagnostics. + // ObjectImmutableArraySequenceEqualityComparer applies element-wise equality over + // the heterogeneous result array, enabling Roslyn's incremental pipeline to skip + // re-emitting source when the model has not changed. + IncrementalValueProvider> sourceModel = + collected.Select(static (t, _) => t.Results).WithComparer(new ObjectImmutableArraySequenceEqualityComparer()); + + context.RegisterSourceOutput(sourceModel, static (context, results) => + { + if (results.IsEmpty) { return; } @@ -168,17 +192,16 @@ public void Initialize(IncrementalGeneratorInitializationContext context) // pair is the implementation used for the key. var emittedExpressions = new Dictionary<(string Pattern, RegexOptions Options, int? Timeout), RegexMethod>(); - // If we have any (RegexMethod regexMethod, string generatedName, string reason, DiagnosticData diagnostic), these are regexes for which we have - // limited support and need to simply output boilerplate. We need to emit their diagnostics. - // If we have any (RegexMethod regexMethod, string generatedName, string runnerFactoryImplementation, Dictionary requiredHelpers), + // If we have any (RegexMethod regexMethod, string reason, CompilationData compilationData), these are regexes for which we have + // limited support and need to simply output boilerplate. + // If we have any (RegexMethod regexMethod, string runnerFactoryImplementation, Dictionary requiredHelpers, CompilationData compilationData), // those are generated implementations to be emitted. We need to gather up their required helpers. Dictionary requiredHelpers = new(); foreach (object? result in results) { RegexMethod? regexMethod = null; - if (result is ValueTuple limitedSupportResult) + if (result is ValueTuple limitedSupportResult) { - context.ReportDiagnostic(limitedSupportResult.Item3.ToDiagnostic()); regexMethod = limitedSupportResult.Item1; } else if (result is ValueTuple, CompilationData> regexImpl) @@ -238,11 +261,11 @@ public void Initialize(IncrementalGeneratorInitializationContext context) writer.Indent++; foreach (object? result in results) { - if (result is ValueTuple limitedSupportResult) + if (result is ValueTuple limitedSupportResult) { if (!limitedSupportResult.Item1.IsDuplicate) { - EmitRegexLimitedBoilerplate(writer, limitedSupportResult.Item1, limitedSupportResult.Item2, limitedSupportResult.Item4.LanguageVersion); + EmitRegexLimitedBoilerplate(writer, limitedSupportResult.Item1, limitedSupportResult.Item2, limitedSupportResult.Item3.LanguageVersion); writer.WriteLine(); } } @@ -290,6 +313,22 @@ public void Initialize(IncrementalGeneratorInitializationContext context) // Save out the source context.AddSource("RegexGenerator.g.cs", sw.ToString()); }); + + // Project to just the diagnostics, discarding the model. ImmutableArray does not + // implement value equality, so Roslyn's incremental pipeline uses reference equality — + // the callback fires on every compilation change. This is by design: diagnostic emission + // is cheap, and we need fresh SourceLocation instances that are pragma-suppressible + // (cf. https://github.com/dotnet/runtime/issues/92509). + IncrementalValueProvider> diagnosticResults = + collected.Select(static (t, _) => t.Diagnostics); + + context.RegisterSourceOutput(diagnosticResults, static (context, diagnostics) => + { + foreach (Diagnostic diagnostic in diagnostics) + { + context.ReportDiagnostic(diagnostic); + } + }); } /// Determines whether the passed in node supports C# code generation. @@ -351,17 +390,6 @@ static bool HasCaseInsensitiveBackReferences(RegexNode node) } } - /// Stores the data necessary to create a Diagnostic. - /// - /// Diagnostics do not have value equality semantics. Storing them in an object model - /// used in the pipeline can result in unnecessary recompilation. - /// - private sealed record class DiagnosticData(DiagnosticDescriptor descriptor, Location location, object? arg = null) - { - /// Create a from the data. - public Diagnostic ToDiagnostic() => Diagnostic.Create(descriptor, location, arg is null ? [] : [arg]); - } - private sealed class ObjectImmutableArraySequenceEqualityComparer : IEqualityComparer> { public bool Equals(ImmutableArray left, ImmutableArray right) diff --git a/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexGeneratorHelper.netcoreapp.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexGeneratorHelper.netcoreapp.cs index 677bf16d32ff0a..946b1d2f1be6e9 100644 --- a/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexGeneratorHelper.netcoreapp.cs +++ b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexGeneratorHelper.netcoreapp.cs @@ -69,7 +69,7 @@ internal static byte[] CreateAssemblyImage(string source, string assemblyName) throw new InvalidOperationException(); } - private static async Task<(Compilation, GeneratorDriverRunResult)> RunGeneratorCore( + internal static async Task<(Compilation, GeneratorDriverRunResult)> RunGeneratorCore( string code, LanguageVersion langVersion = LanguageVersion.Preview, MetadataReference[]? additionalRefs = null, bool allowUnsafe = false, bool checkOverflow = true, CancellationToken cancellationToken = default) { var proj = new AdhocWorkspace() diff --git a/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexGeneratorParserTests.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexGeneratorParserTests.cs index b4d46d8274f57a..3ab5a2923ccf90 100644 --- a/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexGeneratorParserTests.cs +++ b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexGeneratorParserTests.cs @@ -3,8 +3,10 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.DotNet.RemoteExecutor; using System.Collections.Generic; +using System.Collections.Immutable; using System.Diagnostics; using System.Linq; using System.Globalization; @@ -398,6 +400,26 @@ partial class C Assert.Equal("SYSLIB1043", Assert.Single(diagnostics).Id); } + [Fact] + public async Task Diagnostic_HasPragmaSuppressibleLocation() + { + // SYSLIB1044 (LimitedSourceGeneration) is emitted for case-insensitive backreferences. + string code = """ + #pragma warning disable SYSLIB1044 + using System.Text.RegularExpressions; + partial class C + { + [GeneratedRegex("(a)\\1", RegexOptions.IgnoreCase)] + private static partial Regex Method(); + } + """; + + (Compilation comp, GeneratorDriverRunResult result) = await RegexGeneratorHelper.RunGeneratorCore(code); + var effective = CompilationWithAnalyzers.GetEffectiveDiagnostics(result.Diagnostics, comp); + Diagnostic diagnostic = Assert.Single(effective, d => d.Id == "SYSLIB1044"); + Assert.True(diagnostic.IsSuppressed); + } + [Fact] public async Task Diagnostic_PropertyMustHaveGetter() { diff --git a/src/libraries/apicompat/ApiCompatBaseline.NetCoreAppLatestStable.xml b/src/libraries/apicompat/ApiCompatBaseline.NetCoreAppLatestStable.xml index 80edf8a7cd7580..962980d5042fc3 100644 --- a/src/libraries/apicompat/ApiCompatBaseline.NetCoreAppLatestStable.xml +++ b/src/libraries/apicompat/ApiCompatBaseline.NetCoreAppLatestStable.xml @@ -1,6 +1,102 @@ + + CP0002 + M:System.Runtime.Intrinsics.Arm.Sve.GatherVectorUInt32WithByteOffsetsZeroExtend(System.Numerics.Vector{System.Int32},System.UInt32*,System.Numerics.Vector{System.Int32}) + net10.0/System.Runtime.Intrinsics.dll + net11.0/System.Runtime.Intrinsics.dll + + + CP0002 + M:System.Runtime.Intrinsics.Arm.Sve.GatherVectorUInt32WithByteOffsetsZeroExtend(System.Numerics.Vector{System.Int32},System.UInt32*,System.Numerics.Vector{System.UInt32}) + net10.0/System.Runtime.Intrinsics.dll + net11.0/System.Runtime.Intrinsics.dll + + + CP0002 + M:System.Runtime.Intrinsics.Arm.Sve.GatherVectorUInt32WithByteOffsetsZeroExtend(System.Numerics.Vector{System.UInt32},System.UInt32*,System.Numerics.Vector{System.Int32}) + net10.0/System.Runtime.Intrinsics.dll + net11.0/System.Runtime.Intrinsics.dll + + + CP0002 + M:System.Runtime.Intrinsics.Arm.Sve.GatherVectorUInt32WithByteOffsetsZeroExtend(System.Numerics.Vector{System.UInt32},System.UInt32*,System.Numerics.Vector{System.UInt32}) + net10.0/System.Runtime.Intrinsics.dll + net11.0/System.Runtime.Intrinsics.dll + + + CP0002 + M:System.Runtime.Intrinsics.Arm.Sve.GatherVectorUInt32WithByteOffsetsZeroExtendFirstFaulting(System.Numerics.Vector{System.Int32},System.UInt32*,System.Numerics.Vector{System.Int32}) + net10.0/System.Runtime.Intrinsics.dll + net11.0/System.Runtime.Intrinsics.dll + + + CP0002 + M:System.Runtime.Intrinsics.Arm.Sve.GatherVectorUInt32WithByteOffsetsZeroExtendFirstFaulting(System.Numerics.Vector{System.Int32},System.UInt32*,System.Numerics.Vector{System.UInt32}) + net10.0/System.Runtime.Intrinsics.dll + net11.0/System.Runtime.Intrinsics.dll + + + CP0002 + M:System.Runtime.Intrinsics.Arm.Sve.GatherVectorUInt32WithByteOffsetsZeroExtendFirstFaulting(System.Numerics.Vector{System.UInt32},System.UInt32*,System.Numerics.Vector{System.Int32}) + net10.0/System.Runtime.Intrinsics.dll + net11.0/System.Runtime.Intrinsics.dll + + + CP0002 + M:System.Runtime.Intrinsics.Arm.Sve.GatherVectorUInt32WithByteOffsetsZeroExtendFirstFaulting(System.Numerics.Vector{System.UInt32},System.UInt32*,System.Numerics.Vector{System.UInt32}) + net10.0/System.Runtime.Intrinsics.dll + net11.0/System.Runtime.Intrinsics.dll + + + CP0002 + M:System.Runtime.Intrinsics.Arm.Sve.GatherVectorUInt32ZeroExtend(System.Numerics.Vector{System.Int32},System.UInt32*,System.Numerics.Vector{System.Int32}) + net10.0/System.Runtime.Intrinsics.dll + net11.0/System.Runtime.Intrinsics.dll + + + CP0002 + M:System.Runtime.Intrinsics.Arm.Sve.GatherVectorUInt32ZeroExtend(System.Numerics.Vector{System.Int32},System.UInt32*,System.Numerics.Vector{System.UInt32}) + net10.0/System.Runtime.Intrinsics.dll + net11.0/System.Runtime.Intrinsics.dll + + + CP0002 + M:System.Runtime.Intrinsics.Arm.Sve.GatherVectorUInt32ZeroExtend(System.Numerics.Vector{System.UInt32},System.UInt32*,System.Numerics.Vector{System.Int32}) + net10.0/System.Runtime.Intrinsics.dll + net11.0/System.Runtime.Intrinsics.dll + + + CP0002 + M:System.Runtime.Intrinsics.Arm.Sve.GatherVectorUInt32ZeroExtend(System.Numerics.Vector{System.UInt32},System.UInt32*,System.Numerics.Vector{System.UInt32}) + net10.0/System.Runtime.Intrinsics.dll + net11.0/System.Runtime.Intrinsics.dll + + + CP0002 + M:System.Runtime.Intrinsics.Arm.Sve.GatherVectorUInt32ZeroExtendFirstFaulting(System.Numerics.Vector{System.Int32},System.UInt32*,System.Numerics.Vector{System.Int32}) + net10.0/System.Runtime.Intrinsics.dll + net11.0/System.Runtime.Intrinsics.dll + + + CP0002 + M:System.Runtime.Intrinsics.Arm.Sve.GatherVectorUInt32ZeroExtendFirstFaulting(System.Numerics.Vector{System.Int32},System.UInt32*,System.Numerics.Vector{System.UInt32}) + net10.0/System.Runtime.Intrinsics.dll + net11.0/System.Runtime.Intrinsics.dll + + + CP0002 + M:System.Runtime.Intrinsics.Arm.Sve.GatherVectorUInt32ZeroExtendFirstFaulting(System.Numerics.Vector{System.UInt32},System.UInt32*,System.Numerics.Vector{System.Int32}) + net10.0/System.Runtime.Intrinsics.dll + net11.0/System.Runtime.Intrinsics.dll + + + CP0002 + M:System.Runtime.Intrinsics.Arm.Sve.GatherVectorUInt32ZeroExtendFirstFaulting(System.Numerics.Vector{System.UInt32},System.UInt32*,System.Numerics.Vector{System.UInt32}) + net10.0/System.Runtime.Intrinsics.dll + net11.0/System.Runtime.Intrinsics.dll + CP0002 M:System.Runtime.Intrinsics.Arm.Sve2.AddSaturateWithSignedAddend(System.Numerics.Vector{System.Byte},System.Numerics.Vector{System.SByte}) diff --git a/src/mono/wasm/testassets/BlazorBasicTestApp/App/Layout/NavMenu.razor b/src/mono/wasm/testassets/BlazorBasicTestApp/App/Layout/NavMenu.razor index 345ee43c02f805..3fbc1800325745 100644 --- a/src/mono/wasm/testassets/BlazorBasicTestApp/App/Layout/NavMenu.razor +++ b/src/mono/wasm/testassets/BlazorBasicTestApp/App/Layout/NavMenu.razor @@ -28,7 +28,7 @@ @code { - private bool collapseNavMenu = true; + private bool collapseNavMenu = false; private string? NavMenuCssClass => collapseNavMenu ? "collapse" : null; diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IBuiltInCOM.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IBuiltInCOM.cs index 98391986d0fda9..a355c5601946f9 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IBuiltInCOM.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IBuiltInCOM.cs @@ -30,6 +30,8 @@ public interface IBuiltInCOM : IContract // ccw may be any ComCallWrapper in the chain; the implementation navigates to the start. IEnumerable GetCCWInterfaces(TargetPointer ccw) => throw new NotImplementedException(); IEnumerable GetRCWCleanupList(TargetPointer cleanupListPtr) => throw new NotImplementedException(); + IEnumerable<(TargetPointer MethodTable, TargetPointer Unknown)> GetRCWInterfaces(TargetPointer rcw) => throw new NotImplementedException(); + TargetPointer GetRCWContext(TargetPointer rcw) => throw new NotImplementedException(); } public readonly struct BuiltInCOM : IBuiltInCOM diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs index 767effc40b595e..179e3bc5b05a44 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs @@ -148,6 +148,7 @@ public enum DataType RCWCleanupList, RCW, CtxEntry, + InterfaceEntry, /* GC Data Types */ diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs index eaecb87a838900..b06840d4c35bd2 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs @@ -94,6 +94,7 @@ public static class Globals public const string TearOffAddRefSimple = nameof(TearOffAddRefSimple); public const string TearOffAddRefSimpleInner = nameof(TearOffAddRefSimpleInner); public const string RCWCleanupList = nameof(RCWCleanupList); + public const string RCWInterfaceCacheSize = nameof(RCWInterfaceCacheSize); public const string HashMapSlotsPerBucket = nameof(HashMapSlotsPerBucket); public const string HashMapValueMask = nameof(HashMapValueMask); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/BuiltInCOM_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/BuiltInCOM_1.cs index efecac106ae097..521a7e21421376 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/BuiltInCOM_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/BuiltInCOM_1.cs @@ -198,4 +198,23 @@ private TargetPointer GetSTAThread(Data.RCW rcw) Data.CtxEntry ctxEntry = _target.ProcessedData.GetOrAdd(ctxEntryPtr); return ctxEntry.STAThread; } + + public IEnumerable<(TargetPointer MethodTable, TargetPointer Unknown)> GetRCWInterfaces(TargetPointer rcw) + { + Data.RCW rcwData = _target.ProcessedData.GetOrAdd(rcw); + foreach (Data.InterfaceEntry entry in rcwData.InterfaceEntries) + { + if (entry.Unknown != TargetPointer.Null) + { + yield return (entry.MethodTable, entry.Unknown); + } + } + } + + public TargetPointer GetRCWContext(TargetPointer rcw) + { + Data.RCW rcwData = _target.ProcessedData.GetOrAdd(rcw); + + return rcwData.CtxCookie; + } } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Loader_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Loader_1.cs index 6f789c36dc3986..bf31a0128950d1 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Loader_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Loader_1.cs @@ -12,6 +12,7 @@ namespace Microsoft.Diagnostics.DataContractReader.Contracts; internal readonly struct Loader_1 : ILoader { + private const string DefaultDomainFriendlyName = "DefaultDomain"; private const uint ASSEMBLY_NOTIFYFLAGS_PROFILER_NOTIFIED = 0x1; // Assembly Notify Flag for profiler notification private enum ModuleFlags_1 : uint @@ -135,7 +136,7 @@ string ILoader.GetAppDomainFriendlyName() Data.AppDomain appDomain = _target.ProcessedData.GetOrAdd(_target.ReadPointer(appDomainPointer)); return appDomain.FriendlyName != TargetPointer.Null ? _target.ReadUtf16String(appDomain.FriendlyName) - : string.Empty; + : DefaultDomainFriendlyName; } TargetPointer ILoader.GetModule(ModuleHandle handle) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/InterfaceEntry.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/InterfaceEntry.cs new file mode 100644 index 00000000000000..2beb7fdc8d903d --- /dev/null +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/InterfaceEntry.cs @@ -0,0 +1,19 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.Diagnostics.DataContractReader.Data; + +internal sealed class InterfaceEntry : IData +{ + static InterfaceEntry IData.Create(Target target, TargetPointer address) => new InterfaceEntry(target, address); + public InterfaceEntry(Target target, TargetPointer address) + { + Target.TypeInfo type = target.GetTypeInfo(DataType.InterfaceEntry); + + MethodTable = target.ReadPointer(address + (ulong)type.Fields[nameof(MethodTable)].Offset); + Unknown = target.ReadPointer(address + (ulong)type.Fields[nameof(Unknown)].Offset); + } + + public TargetPointer MethodTable { get; init; } + public TargetPointer Unknown { get; init; } +} diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/RCW.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/RCW.cs index d325653df89633..422a899090c23b 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/RCW.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/RCW.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Collections.Generic; + namespace Microsoft.Diagnostics.DataContractReader.Data; internal sealed class RCW : IData @@ -15,6 +17,17 @@ public RCW(Target target, TargetPointer address) Flags = target.Read(address + (ulong)type.Fields[nameof(Flags)].Offset); CtxCookie = target.ReadPointer(address + (ulong)type.Fields[nameof(CtxCookie)].Offset); CtxEntry = target.ReadPointer(address + (ulong)type.Fields[nameof(CtxEntry)].Offset); + TargetPointer interfaceEntriesAddr = address + (ulong)type.Fields[nameof(InterfaceEntries)].Offset; + + uint cacheSize = target.ReadGlobal(Constants.Globals.RCWInterfaceCacheSize); + Target.TypeInfo entryTypeInfo = target.GetTypeInfo(DataType.InterfaceEntry); + uint entrySize = entryTypeInfo.Size!.Value; + + for (uint i = 0; i < cacheSize; i++) + { + TargetPointer entryAddress = interfaceEntriesAddr + i * entrySize; + InterfaceEntries.Add(target.ProcessedData.GetOrAdd(entryAddress)); + } } public TargetPointer NextCleanupBucket { get; init; } @@ -22,4 +35,5 @@ public RCW(Target target, TargetPointer address) public uint Flags { get; init; } public TargetPointer CtxCookie { get; init; } public TargetPointer CtxEntry { get; init; } + public List InterfaceEntries { get; } = new List(); } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataAppDomain.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataAppDomain.cs index 770c86bdc0bb67..90d2b14c91a899 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataAppDomain.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataAppDomain.cs @@ -5,34 +5,152 @@ using System.Diagnostics; using System.Runtime.InteropServices; using System.Runtime.InteropServices.Marshalling; +using Microsoft.Diagnostics.DataContractReader.Contracts; namespace Microsoft.Diagnostics.DataContractReader.Legacy; [GeneratedComClass] public sealed unsafe partial class ClrDataAppDomain : IXCLRDataAppDomain { + private readonly Target _target; private readonly TargetPointer _appDomain; private readonly IXCLRDataAppDomain? _legacyImpl; public TargetPointer Address => _appDomain; - public ClrDataAppDomain(TargetPointer appDomain, IXCLRDataAppDomain? legacyImpl) + public ClrDataAppDomain(Target target, TargetPointer appDomain, IXCLRDataAppDomain? legacyImpl) { + _target = target; _appDomain = appDomain; _legacyImpl = legacyImpl; } - int IXCLRDataAppDomain.GetProcess(/*IXCLRDataProcess*/ void** process) + int IXCLRDataAppDomain.GetProcess(DacComNullableByRef process) => _legacyImpl is not null ? _legacyImpl.GetProcess(process) : HResults.E_NOTIMPL; int IXCLRDataAppDomain.GetName(uint bufLen, uint* nameLen, char* name) - => _legacyImpl is not null ? _legacyImpl.GetName(bufLen, nameLen, name) : HResults.E_NOTIMPL; + { + int hr = HResults.S_OK; + string friendlyName; + try + { + ILoader loader = _target.Contracts.Loader; + friendlyName = loader.GetAppDomainFriendlyName(); + } + catch (VirtualReadException) + { + // Match native DAC / SOSDacImpl behavior: fall back to empty string + // when the FriendlyName pointer targets unreadable memory. + friendlyName = string.Empty; + } + catch (System.Exception ex) + { + hr = ex.HResult; + friendlyName = string.Empty; + } + + if (hr >= 0) + { + OutputBufferHelpers.CopyStringToBuffer(name, bufLen, nameLen, friendlyName); + + // Match native DAC behavior: return S_FALSE when output is truncated. + uint requiredLen = (uint)friendlyName.Length + 1; + if (name is not null && bufLen > 0 && bufLen < requiredLen) + hr = HResults.S_FALSE; + } + +#if DEBUG + if (_legacyImpl is not null) + { + uint nameLenLocal; + char[] legacyNameBuf = new char[bufLen > 0 ? bufLen : 1]; + int hrLocal; + fixed (char* pLegacyName = legacyNameBuf) + { + hrLocal = _legacyImpl.GetName(bufLen, &nameLenLocal, name is not null ? pLegacyName : null); + } + + Debug.ValidateHResult(hr, hrLocal); + if (hr >= 0) + { + if (nameLen is not null) + Debug.Assert(*nameLen == nameLenLocal, $"cDAC: {*nameLen}, DAC: {nameLenLocal}"); + + if (name is not null && bufLen > 0) + { + // On truncation (S_FALSE), nameLenLocal is the full required length + // which may exceed bufLen. Cap to the actual buffer size. + int compareLen = (int)Math.Min(nameLenLocal, bufLen) - 1; + if (compareLen > 0) + { + string dacName = new string(legacyNameBuf, 0, compareLen); + string cdacName = new string(name, 0, compareLen); + Debug.Assert(dacName == cdacName, $"cDAC: {cdacName}, DAC: {dacName}"); + } + } + } + } +#endif + + return hr; + } int IXCLRDataAppDomain.GetUniqueID(ulong* id) - => _legacyImpl is not null ? _legacyImpl.GetUniqueID(id) : HResults.E_NOTIMPL; + { + int hr = HResults.S_OK; + try + { + if (id is null) + throw new ArgumentNullException(nameof(id)); + + *id = _target.ReadGlobal(Constants.Globals.DefaultADID); + } + catch (System.Exception ex) + { + hr = ex.HResult; + } + +#if DEBUG + if (_legacyImpl is not null && hr >= 0) + { + ulong idLocal; + int hrLocal = _legacyImpl.GetUniqueID(&idLocal); + Debug.ValidateHResult(hr, hrLocal); + Debug.Assert(*id == idLocal, $"cDAC: {*id}, DAC: {idLocal}"); + } +#endif + + return hr; + } int IXCLRDataAppDomain.GetFlags(uint* flags) - => _legacyImpl is not null ? _legacyImpl.GetFlags(flags) : HResults.E_NOTIMPL; + { + int hr = HResults.S_OK; + try + { + if (flags is null) + throw new ArgumentNullException(nameof(flags)); + + // CLRDATA_DOMAIN_DEFAULT = 0 + *flags = 0; + } + catch (System.Exception ex) + { + hr = ex.HResult; + } + +#if DEBUG + if (_legacyImpl is not null && hr >= 0) + { + uint flagsLocal; + int hrLocal = _legacyImpl.GetFlags(&flagsLocal); + Debug.ValidateHResult(hr, hrLocal); + Debug.Assert(*flags == flagsLocal, $"cDAC: {*flags}, DAC: {flagsLocal}"); + } +#endif + + return hr; + } int IXCLRDataAppDomain.IsSameObject(IXCLRDataAppDomain* appDomain) { @@ -46,7 +164,7 @@ int IXCLRDataAppDomain.IsSameObject(IXCLRDataAppDomain* appDomain) hr = _appDomain == other._appDomain ? HResults.S_OK : HResults.S_FALSE; } } - catch (Exception ex) + catch (System.Exception ex) { hr = ex.HResult; } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataFrame.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataFrame.cs index ced1465e9f1f26..5e325d3399ab01 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataFrame.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataFrame.cs @@ -8,6 +8,7 @@ using System.Runtime.InteropServices; using System.Runtime.InteropServices.Marshalling; using Microsoft.Diagnostics.DataContractReader.Contracts; +using Microsoft.Diagnostics.DataContractReader.Contracts.StackWalkHelpers; namespace Microsoft.Diagnostics.DataContractReader.Legacy; @@ -38,10 +39,95 @@ int IXCLRDataFrame.GetContext( uint contextBufSize, uint* contextSize, [Out, MarshalUsing(CountElementName = nameof(contextBufSize))] byte[] contextBuf) - => _legacyImpl is not null ? _legacyImpl.GetContext(contextFlags, contextBufSize, contextSize, contextBuf) : HResults.E_NOTIMPL; + { + int hr = HResults.S_OK; + try + { + IStackWalk stackWalk = _target.Contracts.StackWalk; + byte[] context = stackWalk.GetRawContext(_dataFrame); + + if (contextSize is not null) + *contextSize = (uint)context.Length; + + // Match native DAC behavior: fail when the buffer is too small, + // and on success copy the full context. + if (contextBufSize < (uint)context.Length) + throw new ArgumentException(); + + if (contextBufSize > 0 && context.Length > 0) + Array.Copy(context, 0, contextBuf, 0, context.Length); + } + catch (System.Exception ex) + { + hr = ex.HResult; + } + +#if DEBUG + if (_legacyImpl is not null) + { + byte[] localContextBuf = new byte[contextBufSize]; + int hrLocal = _legacyImpl.GetContext(contextFlags, contextBufSize, null, localContextBuf); + Debug.ValidateHResult(hr, hrLocal); + + if (hr == HResults.S_OK) + { + IPlatformAgnosticContext contextStruct = IPlatformAgnosticContext.GetContextForPlatform(_target); + IPlatformAgnosticContext localContextStruct = IPlatformAgnosticContext.GetContextForPlatform(_target); + contextStruct.FillFromBuffer(contextBuf); + localContextStruct.FillFromBuffer(localContextBuf); + + Debug.Assert(contextStruct.Equals(localContextStruct)); + } + } +#endif + + return hr; + } - int IXCLRDataFrame.GetAppDomain(/*IXCLRDataAppDomain*/ void** appDomain) - => _legacyImpl is not null ? _legacyImpl.GetAppDomain(appDomain) : HResults.E_NOTIMPL; + int IXCLRDataFrame.GetAppDomain(DacComNullableByRef appDomain) + { + int hr = HResults.S_OK; + + int hrLegacy = HResults.S_OK; + IXCLRDataAppDomain? legacyAppDomain = null; + if (_legacyImpl is not null) + { + DacComNullableByRef legacyAppDomainOut = new(isNullRef: false); + hrLegacy = _legacyImpl.GetAppDomain(legacyAppDomainOut); + if (hrLegacy >= 0) + { + legacyAppDomain = legacyAppDomainOut.Interface; + } + } + + try + { + TargetPointer appDomainPointer = _target.ReadGlobalPointer(Constants.Globals.AppDomain); + TargetPointer appDomainAddr = _target.ReadPointer(appDomainPointer); + + if (appDomainAddr != TargetPointer.Null) + { + appDomain.Interface = new ClrDataAppDomain(_target, appDomainAddr, legacyAppDomain); + } + else + { + hr = HResults.S_FALSE; + } + } + catch (System.Exception ex) + { + hr = ex.HResult; + } + +#if DEBUG + if (_legacyImpl is not null) + { + Debug.ValidateHResult(hr, hrLegacy); + } +#endif + + return hr; + } int IXCLRDataFrame.GetNumArguments(uint* numArgs) { diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataTask.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataTask.cs index 0574546c87705d..99ac0153a4d0fa 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataTask.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataTask.cs @@ -37,7 +37,7 @@ int IXCLRDataTask.GetCurrentAppDomain(DacComNullableByRef ap try { TargetPointer currentAppDomain = _target.ReadPointer(_target.ReadGlobalPointer(Constants.Globals.AppDomain)); - appDomain.Interface = new ClrDataAppDomain(currentAppDomain, legacyAppDomain); + appDomain.Interface = new ClrDataAppDomain(_target, currentAppDomain, legacyAppDomain); } catch (System.Exception ex) { diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ISOSDacInterface.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ISOSDacInterface.cs index b645240cd13525..b19a0c900d175c 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ISOSDacInterface.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ISOSDacInterface.cs @@ -387,6 +387,13 @@ public struct DacpGcHeapAnalyzeData public int heap_analyze_success; // BOOL } +public struct DacpCOMInterfacePointerData +{ + public ClrDataAddress methodTable; + public ClrDataAddress interfacePtr; + public ClrDataAddress comContext; +} + [GeneratedComInterface] [Guid("286CA186-E763-4F61-9760-487D43AE4341")] public unsafe partial interface ISOSEnum @@ -753,7 +760,7 @@ public unsafe partial interface ISOSDacInterface [PreserveSig] int GetRCWData(ClrDataAddress addr, /*struct DacpRCWData */ void* data); [PreserveSig] - int GetRCWInterfaces(ClrDataAddress rcw, uint count, /*struct DacpCOMInterfacePointerData*/ void* interfaces, uint* pNeeded); + int GetRCWInterfaces(ClrDataAddress rcw, uint count, [In, Out, MarshalUsing(CountElementName = nameof(count))] DacpCOMInterfacePointerData[]? interfaces, uint* pNeeded); [PreserveSig] int GetCCWData(ClrDataAddress ccw, /*struct DacpCCWData */ void* data); [PreserveSig] @@ -795,13 +802,6 @@ public unsafe partial interface ISOSDacInterface int GetFailedAssemblyDisplayName(ClrDataAddress assembly, uint count, char* name, uint* pNeeded); }; -public struct DacpCOMInterfacePointerData -{ - public ClrDataAddress methodTable; - public ClrDataAddress interfacePtr; - public ClrDataAddress comContext; -} - #pragma warning disable CS0649 // Field is never assigned to, and will always have its default value public struct DacpExceptionObjectData { diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/IXCLRData.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/IXCLRData.cs index ce62e874c6dc8c..862d9c6956b8c5 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/IXCLRData.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/IXCLRData.cs @@ -382,7 +382,7 @@ int GetContext( [Out, MarshalUsing(CountElementName = nameof(contextBufSize))] byte[] contextBuf); [PreserveSig] - int GetAppDomain(/*IXCLRDataAppDomain*/ void** appDomain); + int GetAppDomain(DacComNullableByRef appDomain); [PreserveSig] int GetNumArguments(uint* numArgs); @@ -587,7 +587,7 @@ int Request( public unsafe partial interface IXCLRDataAppDomain { [PreserveSig] - int GetProcess(/*IXCLRDataProcess*/ void** process); + int GetProcess(DacComNullableByRef process); [PreserveSig] int GetName(uint bufLen, uint* nameLen, char* name); [PreserveSig] diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs index 9753e6caae5a2a..5b3648a94e496a 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs @@ -3390,8 +3390,93 @@ int ISOSDacInterface.GetPrivateBinPaths(ClrDataAddress appDomain, int count, cha } int ISOSDacInterface.GetRCWData(ClrDataAddress addr, void* data) => _legacyImpl is not null ? _legacyImpl.GetRCWData(addr, data) : HResults.E_NOTIMPL; - int ISOSDacInterface.GetRCWInterfaces(ClrDataAddress rcw, uint count, void* interfaces, uint* pNeeded) - => _legacyImpl is not null ? _legacyImpl.GetRCWInterfaces(rcw, count, interfaces, pNeeded) : HResults.E_NOTIMPL; + int ISOSDacInterface.GetRCWInterfaces(ClrDataAddress rcw, uint count, [In, MarshalUsing(CountElementName = nameof(count)), Out] DacpCOMInterfacePointerData[]? interfaces, uint* pNeeded) + { + int hr = HResults.S_OK; +#if DEBUG + int numWritten = 0; +#endif + try + { + if (rcw == 0) + throw new ArgumentException(); + + TargetPointer rcwPtr = rcw.ToTargetPointer(_target); + IBuiltInCOM builtInCom = _target.Contracts.BuiltInCOM; // E_NOTIMPL if not defined (non-Windows) + IEnumerable<(TargetPointer MethodTable, TargetPointer Unknown)> entries = builtInCom.GetRCWInterfaces(rcwPtr); + + if (interfaces == null) + { + if (pNeeded == null) + { + throw new ArgumentException(); + } + else + { + *pNeeded = (uint)entries.Count(); +#if DEBUG + numWritten = (int)*pNeeded; +#endif + } + } + else + { + TargetPointer ctxCookie = builtInCom.GetRCWContext(rcwPtr); + uint itemIndex = 0; + foreach (var (methodTable, unknown) in entries) + { + if (itemIndex >= count) + { +#if DEBUG + numWritten = (int)itemIndex; +#endif + throw new ArgumentException(); + } + + interfaces[itemIndex].methodTable = methodTable.ToClrDataAddress(_target); + interfaces[itemIndex].interfacePtr = unknown.ToClrDataAddress(_target); + interfaces[itemIndex].comContext = ctxCookie.ToClrDataAddress(_target); + itemIndex++; + } + + if (pNeeded != null) + *pNeeded = itemIndex; +#if DEBUG + numWritten = (int)itemIndex; +#endif + } + } + catch (System.Exception ex) + { + hr = ex.HResult; + } + +#if DEBUG + if (_legacyImpl is not null) + { + uint pNeededLocal = 0; + int hrLocal; + DacpCOMInterfacePointerData[]? interfacesLocal = interfaces != null ? new DacpCOMInterfacePointerData[count] : null; + hrLocal = _legacyImpl.GetRCWInterfaces(rcw, count, interfacesLocal, pNeeded == null && interfacesLocal == null ? null : &pNeededLocal); + Debug.ValidateHResult(hr, hrLocal); + if (hr == HResults.S_OK) + { + Debug.Assert(numWritten == pNeededLocal, $"cDAC: {numWritten}, DAC: {pNeededLocal}"); + if (interfacesLocal is not null && interfaces is not null) + { + for (int i = 0; i < (int)pNeededLocal; i++) + { + Debug.Assert(interfaces[i].methodTable == interfacesLocal![i].methodTable, $"cDAC: {interfaces[i].methodTable:x}, DAC: {interfacesLocal[i].methodTable:x}"); + Debug.Assert(interfaces[i].interfacePtr == interfacesLocal![i].interfacePtr, $"cDAC: {interfaces[i].interfacePtr:x}, DAC: {interfacesLocal[i].interfacePtr:x}"); + Debug.Assert(interfaces[i].comContext == interfacesLocal![i].comContext, $"cDAC: {interfaces[i].comContext:x}, DAC: {interfacesLocal[i].comContext:x}"); + } + } + } + } +#endif + + return hr; + } int ISOSDacInterface.GetRegisterName(int regName, uint count, char* buffer, uint* pNeeded) { int hr = HResults.S_OK; @@ -4119,7 +4204,7 @@ int ISOSDacInterface.TraverseRCWCleanupList(ClrDataAddress cleanupListPtr, deleg if (pCallback is null) throw new ArgumentException(); - Contracts.IBuiltInCOM contract = _target.Contracts.BuiltInCOM; + Contracts.IBuiltInCOM contract = _target.Contracts.BuiltInCOM; // E_NOTIMPL if not defined (non-Windows) TargetPointer listPtr = cleanupListPtr.ToTargetPointer(_target); cleanupInfos = contract.GetRCWCleanupList(listPtr); diff --git a/src/native/managed/cdac/tests/BuiltInCOMTests.cs b/src/native/managed/cdac/tests/BuiltInCOMTests.cs index 3da3ec04d531de..f2b9e86c81e5ef 100644 --- a/src/native/managed/cdac/tests/BuiltInCOMTests.cs +++ b/src/native/managed/cdac/tests/BuiltInCOMTests.cs @@ -12,6 +12,105 @@ namespace Microsoft.Diagnostics.DataContractReader.Tests; public class BuiltInCOMTests { + private const ulong AllocationRangeStart = 0x00000000_20000000; + private const ulong AllocationRangeEnd = 0x00000000_30000000; + + private const uint TestRCWInterfaceCacheSize = 8; + + private static readonly MockDescriptors.TypeFields RCWFields = new MockDescriptors.TypeFields() + { + DataType = DataType.RCW, + Fields = + [ + new(nameof(Data.RCW.NextCleanupBucket), DataType.pointer), + new(nameof(Data.RCW.NextRCW), DataType.pointer), + new(nameof(Data.RCW.Flags), DataType.uint32), + new(nameof(Data.RCW.CtxCookie), DataType.pointer), + new(nameof(Data.RCW.CtxEntry), DataType.pointer), + new(nameof(Data.RCW.InterfaceEntries), DataType.pointer), + ] + }; + + private static readonly MockDescriptors.TypeFields InterfaceEntryFields = new MockDescriptors.TypeFields() + { + DataType = DataType.InterfaceEntry, + Fields = + [ + new(nameof(Data.InterfaceEntry.MethodTable), DataType.pointer), + new(nameof(Data.InterfaceEntry.Unknown), DataType.pointer), + ] + }; + + private static void BuiltInCOMContractHelper( + MockTarget.Architecture arch, + Action> configure, + Action testCase) + { + TargetTestHelpers targetTestHelpers = new(arch); + MockMemorySpace.Builder builder = new(targetTestHelpers); + + Dictionary types = MockDescriptors.GetTypesForTypeFields( + targetTestHelpers, + [RCWFields, InterfaceEntryFields]); + + configure(builder, targetTestHelpers, types); + + (string Name, ulong Value)[] globals = + [ + (nameof(Constants.Globals.RCWInterfaceCacheSize), TestRCWInterfaceCacheSize), + ]; + + var target = new TestPlaceholderTarget(arch, builder.GetMemoryContext().ReadFromTarget, types, globals); + target.SetContracts(Mock.Of( + c => c.BuiltInCOM == ((IContractFactory)new BuiltInCOMFactory()).CreateContract(target, 1))); + + testCase(target); + } + + /// + /// Allocates an RCW mock with the interface entries embedded inline (matching the real C++ layout + /// where m_aInterfaceEntries is an inline array within the RCW struct). + /// Returns the address of the RCW. + /// + private static TargetPointer AddRCWWithInlineEntries( + MockMemorySpace.Builder builder, + TargetTestHelpers targetTestHelpers, + Dictionary types, + MockMemorySpace.BumpAllocator allocator, + (TargetPointer MethodTable, TargetPointer Unknown)[] entries, + TargetPointer ctxCookie = default) + { + Target.TypeInfo rcwTypeInfo = types[DataType.RCW]; + Target.TypeInfo entryTypeInfo = types[DataType.InterfaceEntry]; + uint entrySize = entryTypeInfo.Size!.Value; + uint entriesOffset = (uint)rcwTypeInfo.Fields[nameof(Data.RCW.InterfaceEntries)].Offset; + + // The RCW block must be large enough to hold the RCW header plus all inline entries + uint totalSize = entriesOffset + entrySize * TestRCWInterfaceCacheSize; + MockMemorySpace.HeapFragment fragment = allocator.Allocate(totalSize, "RCW with inline entries"); + Span data = fragment.Data; + + // Write RCW header fields + targetTestHelpers.WritePointer( + data.Slice(rcwTypeInfo.Fields[nameof(Data.RCW.CtxCookie)].Offset), + ctxCookie); + + // Write the inline interface entries starting at entriesOffset + for (int i = 0; i < entries.Length && i < TestRCWInterfaceCacheSize; i++) + { + Span entryData = data.Slice((int)(entriesOffset + i * entrySize)); + targetTestHelpers.WritePointer( + entryData.Slice(entryTypeInfo.Fields[nameof(Data.InterfaceEntry.MethodTable)].Offset), + entries[i].MethodTable); + targetTestHelpers.WritePointer( + entryData.Slice(entryTypeInfo.Fields[nameof(Data.InterfaceEntry.Unknown)].Offset), + entries[i].Unknown); + } + + builder.AddHeapFragment(fragment); + return fragment.Address; + } + // Flag values matching the C++ runtime private const ulong IsLayoutCompleteFlag = 0x10; @@ -473,6 +572,40 @@ public void GetCCWInterfaces_LinkedWrapper_WalksFullChainFromAnyWrapper(MockTarg } } + [Theory] + [ClassData(typeof(MockTarget.StdArch))] + public void GetRCWInterfaces_ReturnsFilledEntries(MockTarget.Architecture arch) + { + TargetPointer rcwAddress = default; + (TargetPointer MethodTable, TargetPointer Unknown)[] expectedEntries = + [ + (new TargetPointer(0x1000), new TargetPointer(0x2000)), + (new TargetPointer(0x3000), new TargetPointer(0x4000)), + ]; + + BuiltInCOMContractHelper(arch, + (builder, targetTestHelpers, types) => + { + MockMemorySpace.BumpAllocator allocator = builder.CreateAllocator(AllocationRangeStart, AllocationRangeEnd); + rcwAddress = AddRCWWithInlineEntries(builder, targetTestHelpers, types, allocator, expectedEntries); + }, + (target) => + { + IBuiltInCOM contract = target.Contracts.BuiltInCOM; + Assert.NotNull(contract); + + List<(TargetPointer MethodTable, TargetPointer Unknown)> results = + contract.GetRCWInterfaces(rcwAddress).ToList(); + + Assert.Equal(expectedEntries.Length, results.Count); + for (int i = 0; i < expectedEntries.Length; i++) + { + Assert.Equal(expectedEntries[i].MethodTable, results[i].MethodTable); + Assert.Equal(expectedEntries[i].Unknown, results[i].Unknown); + } + }); + } + [Theory] [ClassData(typeof(MockTarget.StdArch))] public void GetCCWInterfaces_ComIpAddress_ResolvesToCCW(MockTarget.Architecture arch) @@ -566,6 +699,84 @@ public void GetCCWInterfaces_ComIpAddress_ResolvesToCCW(MockTarget.Architecture } } + [Theory] + [ClassData(typeof(MockTarget.StdArch))] + public void GetRCWInterfaces_SkipsEntriesWithNullUnknown(MockTarget.Architecture arch) + { + TargetPointer rcwAddress = default; + // The IsFree() check uses only Unknown == null; entries with Unknown == null are skipped. + (TargetPointer MethodTable, TargetPointer Unknown)[] entries = + [ + (new TargetPointer(0x1000), new TargetPointer(0x2000)), + (TargetPointer.Null, TargetPointer.Null), // free entry (Unknown == null) + (new TargetPointer(0x5000), new TargetPointer(0x6000)), + ]; + + BuiltInCOMContractHelper(arch, + (builder, targetTestHelpers, types) => + { + MockMemorySpace.BumpAllocator allocator = builder.CreateAllocator(AllocationRangeStart, AllocationRangeEnd); + rcwAddress = AddRCWWithInlineEntries(builder, targetTestHelpers, types, allocator, entries); + }, + (target) => + { + IBuiltInCOM contract = target.Contracts.BuiltInCOM; + List<(TargetPointer MethodTable, TargetPointer Unknown)> results = + contract.GetRCWInterfaces(rcwAddress).ToList(); + + // Only the 2 entries with non-null Unknown are returned + Assert.Equal(2, results.Count); + Assert.Equal(new TargetPointer(0x1000), results[0].MethodTable); + Assert.Equal(new TargetPointer(0x2000), results[0].Unknown); + Assert.Equal(new TargetPointer(0x5000), results[1].MethodTable); + Assert.Equal(new TargetPointer(0x6000), results[1].Unknown); + }); + } + + [Theory] + [ClassData(typeof(MockTarget.StdArch))] + public void GetRCWInterfaces_EmptyCache_ReturnsEmpty(MockTarget.Architecture arch) + { + TargetPointer rcwAddress = default; + + BuiltInCOMContractHelper(arch, + (builder, targetTestHelpers, types) => + { + MockMemorySpace.BumpAllocator allocator = builder.CreateAllocator(AllocationRangeStart, AllocationRangeEnd); + rcwAddress = AddRCWWithInlineEntries(builder, targetTestHelpers, types, allocator, []); + }, + (target) => + { + IBuiltInCOM contract = target.Contracts.BuiltInCOM; + List<(TargetPointer MethodTable, TargetPointer Unknown)> results = + contract.GetRCWInterfaces(rcwAddress).ToList(); + + Assert.Empty(results); + }); + } + + [Theory] + [ClassData(typeof(MockTarget.StdArch))] + public void GetRCWContext_ReturnsCtxCookie(MockTarget.Architecture arch) + { + TargetPointer rcwAddress = default; + TargetPointer expectedCookie = new TargetPointer(0xC00C_1E00); + + BuiltInCOMContractHelper(arch, + (builder, targetTestHelpers, types) => + { + MockMemorySpace.BumpAllocator allocator = builder.CreateAllocator(AllocationRangeStart, AllocationRangeEnd); + rcwAddress = AddRCWWithInlineEntries(builder, targetTestHelpers, types, allocator, [], expectedCookie); + }, + (target) => + { + IBuiltInCOM contract = target.Contracts.BuiltInCOM; + TargetPointer result = contract.GetRCWContext(rcwAddress); + + Assert.Equal(expectedCookie, result); + }); + } + [Theory] [ClassData(typeof(MockTarget.StdArch))] public void GetCCWFromInterfacePointer_SCCWIp_ResolvesToStartCCW(MockTarget.Architecture arch) diff --git a/src/native/managed/cdac/tests/DumpTests/Debuggees/RCWInterfaces/Program.cs b/src/native/managed/cdac/tests/DumpTests/Debuggees/RCWInterfaces/Program.cs new file mode 100644 index 00000000000000..de77918bc6e304 --- /dev/null +++ b/src/native/managed/cdac/tests/DumpTests/Debuggees/RCWInterfaces/Program.cs @@ -0,0 +1,119 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.InteropServices; +using System.Runtime.Versioning; + +/// +/// Debuggee for cDAC dump tests — exercises the BuiltInCOM contract's GetRCWInterfaces API. +/// Creates a real RCW for an unmanaged COM object with populated interface cache, +/// then crashes to produce a dump for analysis. +/// This debuggee is Windows-only, as RCW support requires FEATURE_COMINTEROP. +/// +internal static partial class Program +{ + private const int S_OK = 0; + private const int S_FALSE = 1; + private const int RpcEChangedMode = unchecked((int)0x80010106); + private const uint CoInitMultithreaded = 0; + + private static readonly Guid CLSID_StdGlobalInterfaceTable = new("00000323-0000-0000-C000-000000000046"); + private static readonly Guid IID_IUnknown = new("00000000-0000-0000-C000-000000000046"); + + [ComImport] + [Guid("00000146-0000-0000-C000-000000000046")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + private interface IGlobalInterfaceTable + { + [PreserveSig] + int RegisterInterfaceInGlobal(IntPtr pUnk, ref Guid riid, out int pdwCookie); + + [PreserveSig] + int RevokeInterfaceFromGlobal(int dwCookie); + + [PreserveSig] + int GetInterfaceFromGlobal(int dwCookie, ref Guid riid, out IntPtr ppv); + } + + [LibraryImport("ole32.dll")] + private static partial int CoInitializeEx(IntPtr pvReserved, uint dwCoInit); + + [LibraryImport("ole32.dll")] + private static partial void CoUninitialize(); + + private static void Main() + { + if (OperatingSystem.IsWindows()) + { + CreateRcwOnWindows(); + } + + Environment.FailFast("cDAC dump test: RCWInterfaces debuggee intentional crash"); + } + + [SupportedOSPlatform("windows")] + private static void CreateRcwOnWindows() + { + bool callCoUninitialize = false; + int coInitializeResult = CoInitializeEx(IntPtr.Zero, CoInitMultithreaded); + if (coInitializeResult == S_OK || coInitializeResult == S_FALSE) + { + callCoUninitialize = true; + } + else if (coInitializeResult != RpcEChangedMode) + { + Marshal.ThrowExceptionForHR(coInitializeResult); + } + + IntPtr rcwIUnknown = IntPtr.Zero; + IntPtr fetchedIUnknown = IntPtr.Zero; + GCHandle rcwHandle = default; + + try + { + Type comType = Type.GetTypeFromCLSID(CLSID_StdGlobalInterfaceTable, throwOnError: true)!; + object rcwObject = Activator.CreateInstance(comType)!; + + IGlobalInterfaceTable globalInterfaceTable = (IGlobalInterfaceTable)rcwObject; + + rcwIUnknown = Marshal.GetIUnknownForObject(rcwObject); + + Guid iidIUnknown = IID_IUnknown; + int registerResult = globalInterfaceTable.RegisterInterfaceInGlobal(rcwIUnknown, ref iidIUnknown, out int cookie); + Marshal.ThrowExceptionForHR(registerResult); + + int getResult = globalInterfaceTable.GetInterfaceFromGlobal(cookie, ref iidIUnknown, out fetchedIUnknown); + Marshal.ThrowExceptionForHR(getResult); + + int revokeResult = globalInterfaceTable.RevokeInterfaceFromGlobal(cookie); + Marshal.ThrowExceptionForHR(revokeResult); + + // Pin the RCW object in a strong GC handle so the dump test can find it + // by walking the strong handle table (matching how GCRoots debuggee works). + rcwHandle = GCHandle.Alloc(rcwObject, GCHandleType.Normal); + GC.KeepAlive(globalInterfaceTable); + GC.KeepAlive(rcwHandle); + GC.KeepAlive(rcwObject); + } + finally + { + if (fetchedIUnknown != IntPtr.Zero) + { + Marshal.Release(fetchedIUnknown); + } + + if (rcwIUnknown != IntPtr.Zero) + { + Marshal.Release(rcwIUnknown); + } + + GC.KeepAlive(rcwHandle); + + if (callCoUninitialize) + { + CoUninitialize(); + } + } + } +} diff --git a/src/native/managed/cdac/tests/DumpTests/Debuggees/RCWInterfaces/RCWInterfaces.csproj b/src/native/managed/cdac/tests/DumpTests/Debuggees/RCWInterfaces/RCWInterfaces.csproj new file mode 100644 index 00000000000000..69a9ea88447b47 --- /dev/null +++ b/src/native/managed/cdac/tests/DumpTests/Debuggees/RCWInterfaces/RCWInterfaces.csproj @@ -0,0 +1,7 @@ + + + + $(NoWarn);CA1416 + Full + + diff --git a/src/native/managed/cdac/tests/DumpTests/Debuggees/StackWalk/Program.cs b/src/native/managed/cdac/tests/DumpTests/Debuggees/StackWalk/Program.cs index 7fed5894a501b7..d7d671375aacf5 100644 --- a/src/native/managed/cdac/tests/DumpTests/Debuggees/StackWalk/Program.cs +++ b/src/native/managed/cdac/tests/DumpTests/Debuggees/StackWalk/Program.cs @@ -15,19 +15,31 @@ internal static class Program private static void Main() { - MethodA(); + MethodA(0); } [MethodImpl(MethodImplOptions.NoInlining)] - private static void MethodA() + private static void MethodA(int depth) { + if (depth < 0) + return; MethodB(); } [MethodImpl(MethodImplOptions.NoInlining)] private static void MethodB() { - MethodC(); + // The try/finally ensures localObj is stored as a real IL local variable, + // because the evaluation stack is empty at finally-block entry per ECMA-335. + object localObj = new object(); + try + { + MethodC(); + } + finally + { + GC.KeepAlive(localObj); + } } [MethodImpl(MethodImplOptions.NoInlining)] diff --git a/src/native/managed/cdac/tests/DumpTests/DumpTestBase.cs b/src/native/managed/cdac/tests/DumpTests/DumpTestBase.cs index 6c4b4db9cc6c6d..1b02d1debfc59a 100644 --- a/src/native/managed/cdac/tests/DumpTests/DumpTestBase.cs +++ b/src/native/managed/cdac/tests/DumpTests/DumpTestBase.cs @@ -68,14 +68,22 @@ public static IEnumerable TestConfigurations /// attributes on the calling test method. Call this as the first line of every test. /// protected void InitializeDumpTest(TestConfiguration config, [CallerMemberName] string callerName = "") + => InitializeDumpTest(config, DebuggeeName, DumpType, callerName); + + /// + /// Loads the dump for the given using an explicit + /// and . + /// Use this overload when individual test methods need different debuggees. + /// + protected void InitializeDumpTest(TestConfiguration config, string debuggeeName, string dumpType, [CallerMemberName] string callerName = "") { string dumpRoot = GetDumpRoot(); string versionDir = Path.Combine(dumpRoot, config.RuntimeVersion); _dumpInfo = DumpInfo.TryLoad(versionDir); - EvaluateSkipAttributes(config, callerName); + EvaluateSkipAttributes(config, callerName, dumpType); - string dumpPath = Path.Combine(versionDir, DumpType, DebuggeeName, $"{DebuggeeName}.dmp"); + string dumpPath = Path.Combine(versionDir, dumpType, debuggeeName, $"{debuggeeName}.dmp"); Assert.True(File.Exists(dumpPath), $"Dump file not found: {dumpPath}"); @@ -103,9 +111,9 @@ public void Dispose() /// Checks the calling test method for skip attributes and throws /// if the current configuration matches. /// - private void EvaluateSkipAttributes(TestConfiguration config, string callerName) + private void EvaluateSkipAttributes(TestConfiguration config, string callerName, string? dumpType = null) { - if (config.RuntimeVersion is "net10.0" && DumpType == "heap") + if (config.RuntimeVersion is "net10.0" && (dumpType ?? DumpType) == "heap") { throw new SkipTestException($"[net10.0] Skipping heap dump tests due to outdated dump generation."); } diff --git a/src/native/managed/cdac/tests/DumpTests/IXCLRDataAppDomainDumpTests.cs b/src/native/managed/cdac/tests/DumpTests/IXCLRDataAppDomainDumpTests.cs new file mode 100644 index 00000000000000..a4e01f3b5f1100 --- /dev/null +++ b/src/native/managed/cdac/tests/DumpTests/IXCLRDataAppDomainDumpTests.cs @@ -0,0 +1,218 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using Microsoft.Diagnostics.DataContractReader.Contracts; +using Microsoft.Diagnostics.DataContractReader.Legacy; +using Xunit; +using static Microsoft.Diagnostics.DataContractReader.Tests.TestHelpers; + +namespace Microsoft.Diagnostics.DataContractReader.DumpTests; + +/// +/// Dump-based integration tests for IXCLRDataAppDomain methods. +/// Obtains an AppDomain via ClrDataFrame.GetAppDomain from the StackWalk dump. +/// +public unsafe class IXCLRDataAppDomainDumpTests : DumpTestBase +{ + protected override string DebuggeeName => "StackWalk"; + protected override string DumpType => "full"; + + // ========== GetName ========== + + [ConditionalTheory] + [MemberData(nameof(TestConfigurations))] + [SkipOnVersion("net10.0", "InlinedCallFrame.Datum was added after net10.0")] + public void GetName_QueryLengthOnly_ReturnsSizeWithoutBuffer(TestConfiguration config) + { + InitializeDumpTest(config); + IXCLRDataAppDomain appDomain = GetAppDomain(); + + uint nameLen; + int hr = appDomain.GetName(0, &nameLen, null); + + AssertHResult(HResults.S_OK, hr); + Assert.True(nameLen > 1, "Expected nameLen > 1 (name + null terminator)"); + } + + [ConditionalTheory] + [MemberData(nameof(TestConfigurations))] + [SkipOnVersion("net10.0", "InlinedCallFrame.Datum was added after net10.0")] + public void GetName_FullRetrieval_ReturnsNonEmptyName(TestConfiguration config) + { + InitializeDumpTest(config); + IXCLRDataAppDomain appDomain = GetAppDomain(); + + uint nameLen; + int hr = appDomain.GetName(0, &nameLen, null); + AssertHResult(HResults.S_OK, hr); + Assert.True(nameLen <= 1024, "AppDomain name unexpectedly long"); + + char[] nameBuf = new char[nameLen]; + uint nameLen2; + fixed (char* pName = nameBuf) + { + hr = appDomain.GetName(nameLen, &nameLen2, pName); + } + + AssertHResult(HResults.S_OK, hr); + string name = new string(nameBuf, 0, (int)nameLen2 - 1); + Assert.False(string.IsNullOrEmpty(name), "Expected non-empty AppDomain name"); + } + + [ConditionalTheory] + [MemberData(nameof(TestConfigurations))] + [SkipOnVersion("net10.0", "InlinedCallFrame.Datum was added after net10.0")] + public void GetName_NameIsNullTerminated(TestConfiguration config) + { + InitializeDumpTest(config); + IXCLRDataAppDomain appDomain = GetAppDomain(); + + uint nameLen; + int hr = appDomain.GetName(0, &nameLen, null); + AssertHResult(HResults.S_OK, hr); + + char[] nameBuf = new char[nameLen]; + fixed (char* pName = nameBuf) + { + hr = appDomain.GetName(nameLen, null, pName); + AssertHResult(HResults.S_OK, hr); + Assert.Equal('\0', pName[nameLen - 1]); + } + } + + [ConditionalTheory] + [MemberData(nameof(TestConfigurations))] + [SkipOnVersion("net10.0", "InlinedCallFrame.Datum was added after net10.0")] + public void GetName_TruncatedBuffer_ReturnsSFalse(TestConfiguration config) + { + InitializeDumpTest(config); + IXCLRDataAppDomain appDomain = GetAppDomain(); + + uint fullLen; + int hr = appDomain.GetName(0, &fullLen, null); + AssertHResult(HResults.S_OK, hr); + Assert.True(fullLen > 2, "Need a name long enough to truncate"); + + uint truncLen = fullLen - 1; + char[] nameBuf = new char[truncLen]; + uint reportedLen; + fixed (char* pName = nameBuf) + { + hr = appDomain.GetName(truncLen, &reportedLen, pName); + AssertHResult(HResults.S_FALSE, hr); + } + + // neededLen is always the full size, even on truncation. + Assert.Equal(fullLen, reportedLen); + } + + [ConditionalTheory] + [MemberData(nameof(TestConfigurations))] + [SkipOnVersion("net10.0", "InlinedCallFrame.Datum was added after net10.0")] + public void GetName_TruncatedOutput_IsStillNullTerminated(TestConfiguration config) + { + InitializeDumpTest(config); + IXCLRDataAppDomain appDomain = GetAppDomain(); + + uint fullLen; + int hr = appDomain.GetName(0, &fullLen, null); + AssertHResult(HResults.S_OK, hr); + Assert.True(fullLen > 2, "Need a name long enough to truncate"); + + uint truncLen = fullLen - 1; + char[] nameBuf = new char[truncLen]; + fixed (char* pName = nameBuf) + { + appDomain.GetName(truncLen, null, pName); + Assert.Equal('\0', pName[truncLen - 1]); + } + } + + [ConditionalTheory] + [MemberData(nameof(TestConfigurations))] + [SkipOnVersion("net10.0", "InlinedCallFrame.Datum was added after net10.0")] + public void GetName_NeededLenConsistentAcrossCalls(TestConfiguration config) + { + InitializeDumpTest(config); + IXCLRDataAppDomain appDomain = GetAppDomain(); + + uint len1; + int hr = appDomain.GetName(0, &len1, null); + AssertHResult(HResults.S_OK, hr); + + uint len2; + char[] nameBuf = new char[len1]; + fixed (char* pName = nameBuf) + { + hr = appDomain.GetName(len1, &len2, pName); + AssertHResult(HResults.S_OK, hr); + } + + Assert.Equal(len1, len2); + } + + // ========== GetUniqueID ========== + + [ConditionalTheory] + [MemberData(nameof(TestConfigurations))] + [SkipOnVersion("net10.0", "InlinedCallFrame.Datum was added after net10.0")] + public void GetUniqueID_ReturnsOne(TestConfiguration config) + { + InitializeDumpTest(config); + IXCLRDataAppDomain appDomain = GetAppDomain(); + + ulong id; + int hr = appDomain.GetUniqueID(&id); + + AssertHResult(HResults.S_OK, hr); + Assert.Equal(1ul, id); + } + + // ========== GetFlags ========== + + [ConditionalTheory] + [MemberData(nameof(TestConfigurations))] + [SkipOnVersion("net10.0", "InlinedCallFrame.Datum was added after net10.0")] + public void GetFlags_ReturnsDefaultZero(TestConfiguration config) + { + InitializeDumpTest(config); + IXCLRDataAppDomain appDomain = GetAppDomain(); + + uint flags; + int hr = appDomain.GetFlags(&flags); + + AssertHResult(HResults.S_OK, hr); + Assert.Equal(0u, flags); + } + + // ========== Helpers ========== + + private IXCLRDataAppDomain GetAppDomain() + { + IStackWalk stackWalk = Target.Contracts.StackWalk; + ThreadData crashingThread = DumpTestHelpers.FindFailFastThread(Target); + + IStackDataFrameHandle? managedFrame = null; + foreach (IStackDataFrameHandle dataFrame in stackWalk.CreateStackWalk(crashingThread)) + { + TargetPointer md = stackWalk.GetMethodDescPtr(dataFrame); + if (md != TargetPointer.Null) + { + managedFrame = dataFrame; + break; + } + } + + Assert.NotNull(managedFrame); + + ClrDataFrame frame = new ClrDataFrame(Target, managedFrame, legacyImpl: null); + IXCLRDataFrame xclrFrame = frame; + + DacComNullableByRef appDomainOut = new(isNullRef: false); + int hr = xclrFrame.GetAppDomain(appDomainOut); + AssertHResult(HResults.S_OK, hr); + + return appDomainOut.Interface!; + } +} diff --git a/src/native/managed/cdac/tests/DumpTests/IXCLRDataFrameDumpTests.cs b/src/native/managed/cdac/tests/DumpTests/IXCLRDataFrameDumpTests.cs new file mode 100644 index 00000000000000..2784fdab72f8d4 --- /dev/null +++ b/src/native/managed/cdac/tests/DumpTests/IXCLRDataFrameDumpTests.cs @@ -0,0 +1,308 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Linq; +using Microsoft.Diagnostics.DataContractReader.Contracts; +using Microsoft.Diagnostics.DataContractReader.Legacy; +using Xunit; +using static Microsoft.Diagnostics.DataContractReader.Tests.TestHelpers; + +namespace Microsoft.Diagnostics.DataContractReader.DumpTests; + +/// +/// Dump-based integration tests for IXCLRDataFrame methods. +/// +public unsafe class IXCLRDataFrameDumpTests : DumpTestBase +{ + protected override string DebuggeeName => "StackWalk"; + protected override string DumpType => "full"; + + // ========== GetContext ========== + + [ConditionalTheory] + [MemberData(nameof(TestConfigurations))] + [SkipOnVersion("net10.0", "InlinedCallFrame.Datum was added after net10.0")] + public void GetContext_ReturnsNonEmptyContext(TestConfiguration config) + { + InitializeDumpTest(config); + IXCLRDataFrame frame = CreateFrameForFirstManagedFrame(); + + byte[] contextBuf = new byte[4096]; + uint contextSize; + int hr = frame.GetContext(0, (uint)contextBuf.Length, &contextSize, contextBuf); + + AssertHResult(HResults.S_OK, hr); + Assert.True(contextSize > 0, "Expected non-zero context size"); + Assert.True(contextBuf.Take((int)contextSize).Any(b => b != 0), "Expected non-zero context bytes"); + } + + [ConditionalTheory] + [MemberData(nameof(TestConfigurations))] + [SkipOnVersion("net10.0", "InlinedCallFrame.Datum was added after net10.0")] + public void GetContext_ContextSizeMatchesRawContext(TestConfiguration config) + { + InitializeDumpTest(config); + IStackDataFrameHandle dataFrame = GetFirstManagedFrame(); + IXCLRDataFrame frame = new ClrDataFrame(Target, dataFrame, legacyImpl: null); + + byte[] contextBuf = new byte[4096]; + uint contextSize; + int hr = frame.GetContext(0, (uint)contextBuf.Length, &contextSize, contextBuf); + + AssertHResult(HResults.S_OK, hr); + + byte[] rawContext = Target.Contracts.StackWalk.GetRawContext(dataFrame); + Assert.Equal((uint)rawContext.Length, contextSize); + } + + [ConditionalTheory] + [MemberData(nameof(TestConfigurations))] + [SkipOnVersion("net10.0", "InlinedCallFrame.Datum was added after net10.0")] + public void GetContext_ExactSizeBuffer_CopiesAllBytes(TestConfiguration config) + { + InitializeDumpTest(config); + IStackDataFrameHandle dataFrame = GetFirstManagedFrame(); + IXCLRDataFrame frame = new ClrDataFrame(Target, dataFrame, legacyImpl: null); + + byte[] rawContext = Target.Contracts.StackWalk.GetRawContext(dataFrame); + byte[] contextBuf = new byte[rawContext.Length]; + uint contextSize; + int hr = frame.GetContext(0, (uint)contextBuf.Length, &contextSize, contextBuf); + + AssertHResult(HResults.S_OK, hr); + Assert.Equal((uint)rawContext.Length, contextSize); + Assert.True(contextBuf.SequenceEqual(rawContext), "Context bytes should match raw context exactly"); + } + + [ConditionalTheory] + [MemberData(nameof(TestConfigurations))] + [SkipOnVersion("net10.0", "InlinedCallFrame.Datum was added after net10.0")] + public void GetContext_BufferTooSmall_ReturnsInvalidArg_ButSetsContextSize(TestConfiguration config) + { + InitializeDumpTest(config); + IStackDataFrameHandle dataFrame = GetFirstManagedFrame(); + IXCLRDataFrame frame = new ClrDataFrame(Target, dataFrame, legacyImpl: null); + + byte[] rawContext = Target.Contracts.StackWalk.GetRawContext(dataFrame); + Assert.True(rawContext.Length > 0, "Raw context should not be empty for this test."); + + byte[] tinyBuf = new byte[rawContext.Length - 1]; + uint contextSize; + int hr = frame.GetContext(0, (uint)tinyBuf.Length, &contextSize, tinyBuf); + + AssertHResult(HResults.E_INVALIDARG, hr); + Assert.Equal((uint)rawContext.Length, contextSize); + } + + [ConditionalTheory] + [MemberData(nameof(TestConfigurations))] + [SkipOnVersion("net10.0", "InlinedCallFrame.Datum was added after net10.0")] + public void GetContext_OversizedBuffer_SucceedsWithoutCorruptingExtra(TestConfiguration config) + { + InitializeDumpTest(config); + IStackDataFrameHandle dataFrame = GetFirstManagedFrame(); + IXCLRDataFrame frame = new ClrDataFrame(Target, dataFrame, legacyImpl: null); + + byte[] rawContext = Target.Contracts.StackWalk.GetRawContext(dataFrame); + int oversized = rawContext.Length + 128; + byte[] contextBuf = new byte[oversized]; + // Fill extra region with a sentinel to verify it's untouched. + byte sentinel = 0xAB; + for (int i = rawContext.Length; i < oversized; i++) + contextBuf[i] = sentinel; + + uint contextSize; + int hr = frame.GetContext(0, (uint)oversized, &contextSize, contextBuf); + + AssertHResult(HResults.S_OK, hr); + Assert.Equal((uint)rawContext.Length, contextSize); + Assert.True(contextBuf.AsSpan(0, rawContext.Length).SequenceEqual(rawContext), "Copied bytes should match raw context"); + for (int i = rawContext.Length; i < oversized; i++) + Assert.Equal(sentinel, contextBuf[i]); + } + + // ========== GetAppDomain ========== + + [ConditionalTheory] + [MemberData(nameof(TestConfigurations))] + [SkipOnVersion("net10.0", "InlinedCallFrame.Datum was added after net10.0")] + public void GetAppDomain_ReturnsNonNullAppDomain(TestConfiguration config) + { + InitializeDumpTest(config); + IXCLRDataFrame frame = CreateFrameForFirstManagedFrame(); + + DacComNullableByRef appDomainOut = new(isNullRef: false); + int hr = frame.GetAppDomain(appDomainOut); + + AssertHResult(HResults.S_OK, hr); + Assert.NotNull(appDomainOut.Interface); + } + + [ConditionalTheory] + [MemberData(nameof(TestConfigurations))] + [SkipOnVersion("net10.0", "InlinedCallFrame.Datum was added after net10.0")] + public void GetAppDomain_ReturnedObjectHasNonNullAddress(TestConfiguration config) + { + InitializeDumpTest(config); + IXCLRDataFrame frame = CreateFrameForFirstManagedFrame(); + + DacComNullableByRef appDomainOut = new(isNullRef: false); + int hr = frame.GetAppDomain(appDomainOut); + + AssertHResult(HResults.S_OK, hr); + ClrDataAppDomain appDomain = Assert.IsType(appDomainOut.Interface); + Assert.NotEqual(TargetPointer.Null, appDomain.Address); + } + + [ConditionalTheory] + [MemberData(nameof(TestConfigurations))] + [SkipOnVersion("net10.0", "InlinedCallFrame.Datum was added after net10.0")] + public void GetAppDomain_ConsistentAcrossCalls(TestConfiguration config) + { + InitializeDumpTest(config); + IXCLRDataFrame frame = CreateFrameForFirstManagedFrame(); + + DacComNullableByRef out1 = new(isNullRef: false); + DacComNullableByRef out2 = new(isNullRef: false); + int hr1 = frame.GetAppDomain(out1); + int hr2 = frame.GetAppDomain(out2); + + AssertHResult(HResults.S_OK, hr1); + AssertHResult(HResults.S_OK, hr2); + ClrDataAppDomain ad1 = Assert.IsType(out1.Interface); + ClrDataAppDomain ad2 = Assert.IsType(out2.Interface); + Assert.Equal(ad1.Address, ad2.Address); + } + + // ========== GetNumArguments ========== + + [ConditionalTheory] + [MemberData(nameof(TestConfigurations))] + [SkipOnVersion("net10.0", "InlinedCallFrame.Datum was added after net10.0")] + public void GetNumArguments_ReturnsCountMatchingMetadata(TestConfiguration config) + { + InitializeDumpTest(config); + IStackWalk stackWalk = Target.Contracts.StackWalk; + ThreadData crashingThread = DumpTestHelpers.FindFailFastThread(Target); + + foreach (IStackDataFrameHandle dataFrame in stackWalk.CreateStackWalk(crashingThread)) + { + TargetPointer md = stackWalk.GetMethodDescPtr(dataFrame); + if (md == TargetPointer.Null) + continue; + + string? name = DumpTestHelpers.GetMethodName(Target, md); + if (name is not "MethodA") + continue; + + ClrDataFrame frame = new ClrDataFrame(Target, dataFrame, legacyImpl: null); + IXCLRDataFrame xclrFrame = frame; + uint numArgs; + int hr = xclrFrame.GetNumArguments(&numArgs); + + // MethodA(int depth) is static with 1 parameter → numArgs == 1. + AssertHResult(HResults.S_OK, hr); + Assert.Equal(1u, numArgs); + + return; + } + + Assert.Fail("MethodA not found on the crashing thread's stack"); + } + + // ========== GetNumLocalVariables ========== + + [ConditionalTheory] + [MemberData(nameof(TestConfigurations))] + [SkipOnVersion("net10.0", "InlinedCallFrame.Datum was added after net10.0")] + public void GetNumLocalVariables_ReturnsCountForILMethod(TestConfiguration config) + { + InitializeDumpTest(config); + IStackWalk stackWalk = Target.Contracts.StackWalk; + IRuntimeTypeSystem rts = Target.Contracts.RuntimeTypeSystem; + ThreadData crashingThread = DumpTestHelpers.FindFailFastThread(Target); + + foreach (IStackDataFrameHandle dataFrame in stackWalk.CreateStackWalk(crashingThread)) + { + TargetPointer md = stackWalk.GetMethodDescPtr(dataFrame); + if (md == TargetPointer.Null) + continue; + + string? name = DumpTestHelpers.GetMethodName(Target, md); + if (name is not "MethodB") + continue; + + MethodDescHandle mdh = rts.GetMethodDescHandle(md); + Assert.True(rts.IsIL(mdh), "MethodB should be an IL method"); + + ClrDataFrame frame = new ClrDataFrame(Target, dataFrame, legacyImpl: null); + IXCLRDataFrame xclrFrame = frame; + uint numLocals; + int hr = xclrFrame.GetNumLocalVariables(&numLocals); + + AssertHResult(HResults.S_OK, hr); + Assert.True(numLocals >= 1, $"MethodB should have at least 1 local variable, got {numLocals}"); + + return; + } + + Assert.Fail("MethodB not found on the crashing thread's stack"); + } + + // ========== GetMethodInstance ========== + + [ConditionalTheory] + [MemberData(nameof(TestConfigurations))] + [SkipOnVersion("net10.0", "InlinedCallFrame.Datum was added after net10.0")] + public void GetMethodInstance_ReturnsNonNullForManagedFrame(TestConfiguration config) + { + InitializeDumpTest(config); + IStackWalk stackWalk = Target.Contracts.StackWalk; + ThreadData crashingThread = DumpTestHelpers.FindFailFastThread(Target); + + foreach (IStackDataFrameHandle dataFrame in stackWalk.CreateStackWalk(crashingThread)) + { + TargetPointer md = stackWalk.GetMethodDescPtr(dataFrame); + if (md == TargetPointer.Null) + continue; + + ClrDataFrame frame = new ClrDataFrame(Target, dataFrame, legacyImpl: null); + IXCLRDataFrame xclrFrame = frame; + + DacComNullableByRef methodOut = new(isNullRef: false); + int hr = xclrFrame.GetMethodInstance(methodOut); + + AssertHResult(HResults.S_OK, hr); + Assert.NotNull(methodOut.Interface); + + return; // One check is enough. + } + + Assert.Fail("No managed frames with MethodDesc found"); + } + + // ========== Helpers ========== + + private IStackDataFrameHandle GetFirstManagedFrame() + { + IStackWalk stackWalk = Target.Contracts.StackWalk; + ThreadData crashingThread = DumpTestHelpers.FindFailFastThread(Target); + + foreach (IStackDataFrameHandle dataFrame in stackWalk.CreateStackWalk(crashingThread)) + { + TargetPointer md = stackWalk.GetMethodDescPtr(dataFrame); + if (md != TargetPointer.Null) + return dataFrame; + } + + Assert.Fail("No managed frames with MethodDesc found on the crashing thread's stack"); + throw new InvalidOperationException("Unreachable"); + } + + private IXCLRDataFrame CreateFrameForFirstManagedFrame() + { + IStackDataFrameHandle dataFrame = GetFirstManagedFrame(); + return new ClrDataFrame(Target, dataFrame, legacyImpl: null); + } +} diff --git a/src/native/managed/cdac/tests/DumpTests/RCWInterfacesDumpTests.cs b/src/native/managed/cdac/tests/DumpTests/RCWInterfacesDumpTests.cs new file mode 100644 index 00000000000000..52fb2520eec033 --- /dev/null +++ b/src/native/managed/cdac/tests/DumpTests/RCWInterfacesDumpTests.cs @@ -0,0 +1,75 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; +using System.Linq; +using Microsoft.Diagnostics.DataContractReader.Contracts; +using Xunit; + +namespace Microsoft.Diagnostics.DataContractReader.DumpTests; + +/// +/// Dump-based integration tests for the BuiltInCOM contract's GetRCWInterfaces API. +/// Uses the RCWInterfaces debuggee which creates a COM RCW and populates the +/// inline interface entry cache before crashing. +/// +public class RCWInterfacesDumpTests : DumpTestBase +{ + protected override string DebuggeeName => "RCWInterfaces"; + protected override string DumpType => "full"; + + [ConditionalTheory] + [MemberData(nameof(TestConfigurations))] + [SkipOnOS(IncludeOnly = "windows", Reason = "COM interop (RCW) is only supported on Windows")] + public void GetRCWInterfaces_FindsRCWAndEnumeratesInterfaces(TestConfiguration config) + { + InitializeDumpTest(config); + IBuiltInCOM builtInCOM = Target.Contracts.BuiltInCOM; + IObject objectContract = Target.Contracts.Object; + IGC gcContract = Target.Contracts.GC; + + Assert.NotNull(builtInCOM); + Assert.NotNull(objectContract); + Assert.NotNull(gcContract); + + // Walk all strong GC handles to find objects with COM data (RCWs) + List strongHandles = gcContract.GetHandles([HandleType.Strong]); + TargetPointer rcwPtr = TargetPointer.Null; + + foreach (HandleData handleData in strongHandles) + { + TargetPointer objectAddress = Target.ReadPointer(handleData.Handle); + if (objectAddress == TargetPointer.Null) + continue; + + if (objectContract.GetBuiltInComData(objectAddress, out TargetPointer rcw, out _, out _) + && rcw != TargetPointer.Null) + { + rcwPtr = rcw; + break; + } + } + + Assert.NotEqual(TargetPointer.Null, rcwPtr); + + // Assert that the cookie is not null + TargetPointer cookie = builtInCOM.GetRCWContext(rcwPtr); + Assert.NotEqual(TargetPointer.Null, cookie); + + // Call GetRCWInterfaces on the found RCW — must not throw + List<(TargetPointer MethodTable, TargetPointer Unknown)> interfaces = + builtInCOM.GetRCWInterfaces(rcwPtr).ToList(); + + // The debuggee interacts with the RCW via IGlobalInterfaceTable / IUnknown, + // so the entry cache should have at least one cached interface entry + Assert.True(interfaces.Count >= 1, + $"Expected at least one cached interface entry in the RCW, got {interfaces.Count}"); + + // Every returned entry must have non-null MethodTable and Unknown pointers + foreach ((TargetPointer mt, TargetPointer unk) in interfaces) + { + Assert.NotEqual(TargetPointer.Null, mt); + Assert.NotEqual(TargetPointer.Null, unk); + } + } +} diff --git a/src/tests/Common/GenerateHWIntrinsicTests/Arm/Sve2Tests.cs b/src/tests/Common/GenerateHWIntrinsicTests/Arm/Sve2Tests.cs index 6f3293a8ad96bc..a39293f8d7f325 100644 --- a/src/tests/Common/GenerateHWIntrinsicTests/Arm/Sve2Tests.cs +++ b/src/tests/Common/GenerateHWIntrinsicTests/Arm/Sve2Tests.cs @@ -299,6 +299,107 @@ static class Sve2Tests (Templates.SveVecBinOpTest, new Dictionary { ["TestName"] = "Sve2_FusedAddRoundedHalving_uint", ["Method"] = "FusedAddRoundedHalving", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ConvertFunc"] = "", ["ValidateIterResult"] = "result[i] != Helpers.FusedAddRoundedHalving(left[i], right[i])", ["GetIterResult"] = "Helpers.FusedAddRoundedHalving(leftOp[i], rightOp[i])",}), (Templates.SveVecBinOpTest, new Dictionary { ["TestName"] = "Sve2_FusedAddRoundedHalving_ulong", ["Method"] = "FusedAddRoundedHalving", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ConvertFunc"] = "", ["ValidateIterResult"] = "result[i] != Helpers.FusedAddRoundedHalving(left[i], right[i])", ["GetIterResult"] = "Helpers.FusedAddRoundedHalving(leftOp[i], rightOp[i])",}), + // (Templates.SveGatherVectorVectorBases,new Dictionary {["TestName"] = "Sve2_GatherVectorByteZeroExtendNonTemporal_Bases_int_uint", ["Method"] = "GatherVectorByteZeroExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt32", ["ExtendedElementType"] = "Byte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()" ["NextValueBase"] = "TestLibrary.Generator.GetInt32()"}), + // (Templates.SveGatherVectorVectorBases,new Dictionary {["TestName"] = "Sve2_GatherVectorByteZeroExtendNonTemporal_Bases_uint_uint", ["Method"] = "GatherVectorByteZeroExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt32", ["ExtendedElementType"] = "Byte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()" ["NextValueBase"] = "TestLibrary.Generator.GetUInt32()"}), + (Templates.SveGatherVectorVectorBases, new Dictionary {["TestName"] = "Sve2_GatherVectorByteZeroExtendNonTemporal_Bases_long_ulong", ["Method"] = "GatherVectorByteZeroExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt64", ["ExtendedElementType"] = "Byte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["NextValueBase"] = "TestLibrary.Generator.GetInt64()"}), + (Templates.SveGatherVectorVectorBases, new Dictionary {["TestName"] = "Sve2_GatherVectorByteZeroExtendNonTemporal_Bases_ulong_ulong", ["Method"] = "GatherVectorByteZeroExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt64", ["ExtendedElementType"] = "Byte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["NextValueBase"] = "TestLibrary.Generator.GetUInt64()" }), + (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve2_GatherVectorByteZeroExtendNonTemporal_Indices_int_uint", ["Method"] = "GatherVectorByteZeroExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["Op2BaseType"] = "Byte", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt32", ["ExtendedElementType"] = "Byte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["AreOffsets"] = "false"}), + (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve2_GatherVectorByteZeroExtendNonTemporal_Indices_uint_uint", ["Method"] = "GatherVectorByteZeroExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "Byte", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt32", ["ExtendedElementType"] = "Byte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["AreOffsets"] = "false"}), + (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve2_GatherVectorByteZeroExtendNonTemporal_Indices_long_long", ["Method"] = "GatherVectorByteZeroExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "Byte", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int64", ["ExtendedElementType"] = "Byte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt64()", ["AreOffsets"] = "false"}), + (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve2_GatherVectorByteZeroExtendNonTemporal_Indices_ulong_long", ["Method"] = "GatherVectorByteZeroExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "Byte", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int64", ["ExtendedElementType"] = "Byte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt64()", ["AreOffsets"] = "false"}), + (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve2_GatherVectorByteZeroExtendNonTemporal_Indices_long_ulong", ["Method"] = "GatherVectorByteZeroExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "Byte", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt64", ["ExtendedElementType"] = "Byte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt64()", ["AreOffsets"] = "false"}), + (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve2_GatherVectorByteZeroExtendNonTemporal_Indices_ulong_ulong", ["Method"] = "GatherVectorByteZeroExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "Byte", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt64", ["ExtendedElementType"] = "Byte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt64()", ["AreOffsets"] = "false"}), + + // (Templates.SveGatherVectorVectorBases, new Dictionary {["TestName"] = "Sve2_GatherVectorInt16SignExtendNonTemporal_Bases_int_uint", ["Method"] = "GatherVectorInt16SignExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt32", ["ExtendedElementType"] = "Int16", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()" ["NextValueBase"] = "TestLibrary.Generator.GetInt32()}), + // (Templates.SveGatherVectorVectorBases, new Dictionary {["TestName"] = "Sve2_GatherVectorInt16SignExtendNonTemporal_Bases_uint_uint", ["Method"] = "GatherVectorInt16SignExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt32", ["ExtendedElementType"] = "Int16", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()" ["NextValueBase"] = "TestLibrary.Generator.GetUInt32()}), + (Templates.SveGatherVectorVectorBases, new Dictionary {["TestName"] = "Sve2_GatherVectorInt16SignExtendNonTemporal_Bases_long_ulong", ["Method"] = "GatherVectorInt16SignExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt64", ["ExtendedElementType"] = "Int16", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["NextValueBase"] = "TestLibrary.Generator.GetInt64()"}), + (Templates.SveGatherVectorVectorBases, new Dictionary {["TestName"] = "Sve2_GatherVectorInt16SignExtendNonTemporal_Bases_ulong_ulong", ["Method"] = "GatherVectorInt16SignExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt64", ["ExtendedElementType"] = "Int16", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["NextValueBase"] = "TestLibrary.Generator.GetUInt64()"}), + (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve2_GatherVectorInt16SignExtendNonTemporal_Indices_long_long", ["Method"] = "GatherVectorInt16SignExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "Int16", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int64", ["ExtendedElementType"] = "Int16", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt64()", ["AreOffsets"] = "false"}), + (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve2_GatherVectorInt16SignExtendNonTemporal_Indices_ulong_long", ["Method"] = "GatherVectorInt16SignExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "Int16", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int64", ["ExtendedElementType"] = "Int16", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt64()", ["AreOffsets"] = "false"}), + (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve2_GatherVectorInt16SignExtendNonTemporal_Indices_long_ulong", ["Method"] = "GatherVectorInt16SignExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "Int16", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt64", ["ExtendedElementType"] = "Int16", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt64()", ["AreOffsets"] = "false"}), + (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve2_GatherVectorInt16SignExtendNonTemporal_Indices_ulong_ulong", ["Method"] = "GatherVectorInt16SignExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "Int16", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt64", ["ExtendedElementType"] = "Int16", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt64()", ["AreOffsets"] = "false"}), + + (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve2_GatherVectorInt16WithByteOffsetsSignExtendNonTemporal_int_uint", ["Method"] = "GatherVectorInt16WithByteOffsetsSignExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["Op2BaseType"] = "Int16", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt32", ["ExtendedElementType"] = "Int16", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["AreOffsets"] = "true"}), + (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve2_GatherVectorInt16WithByteOffsetsSignExtendNonTemporal_uint_uint", ["Method"] = "GatherVectorInt16WithByteOffsetsSignExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "Int16", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt32", ["ExtendedElementType"] = "Int16", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["AreOffsets"] = "true"}), + (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve2_GatherVectorInt16WithByteOffsetsSignExtendNonTemporal_long_long", ["Method"] = "GatherVectorInt16WithByteOffsetsSignExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "Int16", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int64", ["ExtendedElementType"] = "Int16", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt64()", ["AreOffsets"] = "true"}), + (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve2_GatherVectorInt16WithByteOffsetsSignExtendNonTemporal_ulong_long", ["Method"] = "GatherVectorInt16WithByteOffsetsSignExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "Int16", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int64", ["ExtendedElementType"] = "Int16", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt64()", ["AreOffsets"] = "true"}), + (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve2_GatherVectorInt16WithByteOffsetsSignExtendNonTemporal_long_ulong", ["Method"] = "GatherVectorInt16WithByteOffsetsSignExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "Int16", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt64", ["ExtendedElementType"] = "Int16", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt64()", ["AreOffsets"] = "true"}), + (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve2_GatherVectorInt16WithByteOffsetsSignExtendNonTemporal_ulong_ulong", ["Method"] = "GatherVectorInt16WithByteOffsetsSignExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "Int16", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt64", ["ExtendedElementType"] = "Int16", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt64()", ["AreOffsets"] = "true"}), + + (Templates.SveGatherVectorVectorBases, new Dictionary {["TestName"] = "Sve2_GatherVectorInt32SignExtendNonTemporal_Bases_long_ulong", ["Method"] = "GatherVectorInt32SignExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt64", ["ExtendedElementType"] = "Int32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["NextValueBase"] = "TestLibrary.Generator.GetInt64()"}), + (Templates.SveGatherVectorVectorBases, new Dictionary {["TestName"] = "Sve2_GatherVectorInt32SignExtendNonTemporal_Bases_ulong_ulong", ["Method"] = "GatherVectorInt32SignExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt64", ["ExtendedElementType"] = "Int32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["NextValueBase"] = "TestLibrary.Generator.GetUInt64()"}), + (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve2_GatherVectorInt32SignExtendNonTemporal_Indices_long_long", ["Method"] = "GatherVectorInt32SignExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "Int32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int64", ["ExtendedElementType"] = "Int32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt64()", ["AreOffsets"] = "false"}), + (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve2_GatherVectorInt32SignExtendNonTemporal_Indices_ulong_long", ["Method"] = "GatherVectorInt32SignExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "Int32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int64", ["ExtendedElementType"] = "Int32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt64()", ["AreOffsets"] = "false"}), + (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve2_GatherVectorInt32SignExtendNonTemporal_Indices_long_ulong", ["Method"] = "GatherVectorInt32SignExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "Int32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt64", ["ExtendedElementType"] = "Int32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt64()", ["AreOffsets"] = "false"}), + (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve2_GatherVectorInt32SignExtendNonTemporal_Indices_ulong_ulong", ["Method"] = "GatherVectorInt32SignExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "Int32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt64", ["ExtendedElementType"] = "Int32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt64()", ["AreOffsets"] = "false"}), + + (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve2_GatherVectorInt32WithByteOffsetsSignExtendNonTemporal_long_long", ["Method"] = "GatherVectorInt32WithByteOffsetsSignExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "Int32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int64", ["ExtendedElementType"] = "Int32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt64()", ["AreOffsets"] = "true"}), + (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve2_GatherVectorInt32WithByteOffsetsSignExtendNonTemporal_ulong_long", ["Method"] = "GatherVectorInt32WithByteOffsetsSignExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "Int32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int64", ["ExtendedElementType"] = "Int32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt64()", ["AreOffsets"] = "true"}), + (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve2_GatherVectorInt32WithByteOffsetsSignExtendNonTemporal_long_ulong", ["Method"] = "GatherVectorInt32WithByteOffsetsSignExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "Int32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt64", ["ExtendedElementType"] = "Int32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt64()", ["AreOffsets"] = "true"}), + (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve2_GatherVectorInt32WithByteOffsetsSignExtendNonTemporal_ulong_ulong", ["Method"] = "GatherVectorInt32WithByteOffsetsSignExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "Int32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt64", ["ExtendedElementType"] = "Int32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt64()", ["AreOffsets"] = "true"}), + + // (Templates.SveGatherVectorVectorBases, new Dictionary { ["TestName"] = "Sve2_GatherVectorNonTemporal_Bases_float_uint", ["Method"] = "GatherVectorNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt32", ["ExtendedElementType"] = "Single", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueBase"] = "TestLibrary.Generator.GetSingle()"}), + // (Templates.SveGatherVectorVectorBases, new Dictionary { ["TestName"] = "Sve2_GatherVectorNonTemporal_Bases_int_uint", ["Method"] = "GatherVectorNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt32", ["ExtendedElementType"] = "Int32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueBase"] = "TestLibrary.Generator.GetInt32()"}), + // (Templates.SveGatherVectorVectorBases, new Dictionary { ["TestName"] = "Sve2_GatherVectorNonTemporal_Bases_uint_uint", ["Method"] = "GatherVectorNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt32", ["ExtendedElementType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueBase"] = "TestLibrary.Generator.GetUInt32()"}), + (Templates.SveGatherVectorVectorBases, new Dictionary { ["TestName"] = "Sve2_GatherVectorNonTemporal_Bases_double_ulong", ["Method"] = "GatherVectorNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt64", ["ExtendedElementType"] = "Double", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["NextValueBase"] = "TestLibrary.Generator.GetDouble()"}), + (Templates.SveGatherVectorVectorBases, new Dictionary { ["TestName"] = "Sve2_GatherVectorNonTemporal_Bases_long_ulong", ["Method"] = "GatherVectorNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt64", ["ExtendedElementType"] = "Int64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["NextValueBase"] = "TestLibrary.Generator.GetInt64()"}), + (Templates.SveGatherVectorVectorBases, new Dictionary { ["TestName"] = "Sve2_GatherVectorNonTemporal_Bases_ulong_ulong", ["Method"] = "GatherVectorNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt64", ["ExtendedElementType"] = "UInt64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["NextValueBase"] = "TestLibrary.Generator.GetUInt64()"}), + (Templates.SveGatherVector, new Dictionary { ["TestName"] = "Sve2_GatherVectorNonTemporal_Indices_double_long", ["Method"] = "GatherVectorNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Double", ["Op2BaseType"] = "Double", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int64", ["ExtendedElementType"] = "Double", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt64()", ["AreOffsets"] = "false"}), + (Templates.SveGatherVector, new Dictionary { ["TestName"] = "Sve2_GatherVectorNonTemporal_Indices_long_long", ["Method"] = "GatherVectorNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "Int64", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int64", ["ExtendedElementType"] = "Int64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt64()", ["AreOffsets"] = "false"}), + (Templates.SveGatherVector, new Dictionary { ["TestName"] = "Sve2_GatherVectorNonTemporal_Indices_ulong_long", ["Method"] = "GatherVectorNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "UInt64", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int64", ["ExtendedElementType"] = "UInt64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt64()", ["AreOffsets"] = "false"}), + (Templates.SveGatherVector, new Dictionary { ["TestName"] = "Sve2_GatherVectorNonTemporal_Indices_double_ulong", ["Method"] = "GatherVectorNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Double", ["Op2BaseType"] = "Double", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt64", ["ExtendedElementType"] = "Double", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt64()", ["AreOffsets"] = "false"}), + (Templates.SveGatherVector, new Dictionary { ["TestName"] = "Sve2_GatherVectorNonTemporal_Indices_long_ulong", ["Method"] = "GatherVectorNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "Int64", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt64", ["ExtendedElementType"] = "Int64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt64()", ["AreOffsets"] = "false"}), + (Templates.SveGatherVector, new Dictionary { ["TestName"] = "Sve2_GatherVectorNonTemporal_Indices_ulong_ulong", ["Method"] = "GatherVectorNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "UInt64", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt64", ["ExtendedElementType"] = "UInt64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt64()", ["AreOffsets"] = "false"}), + + (Templates.SveGatherVectorByteOffsets, new Dictionary {["TestName"] = "Sve2_GatherVectorWithByteOffsetsNonTemporal_float_uint", ["Method"] = "GatherVectorWithByteOffsetsNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Single", ["Op2BaseType"] = "Single", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt32", ["ExtendedElementType"] = "Byte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["ConvertFunc"] = "BitConverter.SingleToInt32Bits"}), + (Templates.SveGatherVectorByteOffsets, new Dictionary {["TestName"] = "Sve2_GatherVectorWithByteOffsetsNonTemporal_int_uint", ["Method"] = "GatherVectorWithByteOffsetsNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["Op2BaseType"] = "Int32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt32", ["ExtendedElementType"] = "Byte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["ConvertFunc"] = ""}), + (Templates.SveGatherVectorByteOffsets, new Dictionary {["TestName"] = "Sve2_GatherVectorWithByteOffsetsNonTemporal_uint_uint", ["Method"] = "GatherVectorWithByteOffsetsNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt32", ["ExtendedElementType"] = "Byte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["ConvertFunc"] = ""}), + (Templates.SveGatherVectorByteOffsets, new Dictionary {["TestName"] = "Sve2_GatherVectorWithByteOffsetsNonTemporal_double_long", ["Method"] = "GatherVectorWithByteOffsetsNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Double", ["Op2BaseType"] = "Double", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int64", ["ExtendedElementType"] = "Byte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt64()", ["ConvertFunc"] = "BitConverter.DoubleToInt64Bits"}), + (Templates.SveGatherVectorByteOffsets, new Dictionary {["TestName"] = "Sve2_GatherVectorWithByteOffsetsNonTemporal_long_long", ["Method"] = "GatherVectorWithByteOffsetsNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "Int64", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int64", ["ExtendedElementType"] = "Byte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt64()", ["ConvertFunc"] = ""}), + (Templates.SveGatherVectorByteOffsets, new Dictionary {["TestName"] = "Sve2_GatherVectorWithByteOffsetsNonTemporal_ulong_long", ["Method"] = "GatherVectorWithByteOffsetsNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "UInt64", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int64", ["ExtendedElementType"] = "Byte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt64()", ["ConvertFunc"] = ""}), + (Templates.SveGatherVectorByteOffsets, new Dictionary {["TestName"] = "Sve2_GatherVectorWithByteOffsetsNonTemporal_double_ulong", ["Method"] = "GatherVectorWithByteOffsetsNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Double", ["Op2BaseType"] = "Double", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt64", ["ExtendedElementType"] = "Byte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt64()", ["ConvertFunc"] = "BitConverter.DoubleToInt64Bits"}), + (Templates.SveGatherVectorByteOffsets, new Dictionary {["TestName"] = "Sve2_GatherVectorWithByteOffsetsNonTemporal_long_ulong", ["Method"] = "GatherVectorWithByteOffsetsNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "Int64", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt64", ["ExtendedElementType"] = "Byte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt64()", ["ConvertFunc"] = ""}), + (Templates.SveGatherVectorByteOffsets, new Dictionary {["TestName"] = "Sve2_GatherVectorWithByteOffsetsNonTemporal_ulong_ulong", ["Method"] = "GatherVectorWithByteOffsetsNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "UInt64", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt64", ["ExtendedElementType"] = "Byte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt64()", ["ConvertFunc"] = ""}), + + // (Templates.SveGatherVectorVectorBases, new Dictionary {["TestName"] = "Sve2_GatherVectorSByteSignExtendNonTemporal_Bases_int_uint", ["Method"] = "GatherVectorSByteSignExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt32", ["ExtendedElementType"] = "SByte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueBase"] = "TestLibrary.Generator.GetInt32()"}), + // (Templates.SveGatherVectorVectorBases, new Dictionary {["TestName"] = "Sve2_GatherVectorSByteSignExtendNonTemporal_Bases_uint_uint", ["Method"] = "GatherVectorSByteSignExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt32", ["ExtendedElementType"] = "SByte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueBase"] = "TestLibrary.Generator.GetUInt32()"}), + (Templates.SveGatherVectorVectorBases, new Dictionary {["TestName"] = "Sve2_GatherVectorSByteSignExtendNonTemporal_Bases_long_ulong", ["Method"] = "GatherVectorSByteSignExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt64", ["ExtendedElementType"] = "SByte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["NextValueBase"] = "TestLibrary.Generator.GetInt64()"}), + (Templates.SveGatherVectorVectorBases, new Dictionary {["TestName"] = "Sve2_GatherVectorSByteSignExtendNonTemporal_Bases_ulong_ulong", ["Method"] = "GatherVectorSByteSignExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt64", ["ExtendedElementType"] = "SByte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["NextValueBase"] = "TestLibrary.Generator.GetUInt64()"}), + (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve2_GatherVectorSByteSignExtendNonTemporal_Indices_int_uint", ["Method"] = "GatherVectorSByteSignExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["Op2BaseType"] = "SByte", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt32", ["ExtendedElementType"] = "SByte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["AreOffsets"] = "false" }), + (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve2_GatherVectorSByteSignExtendNonTemporal_Indices_uint_uint", ["Method"] = "GatherVectorSByteSignExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "SByte", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt32", ["ExtendedElementType"] = "SByte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["AreOffsets"] = "false" }), + (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve2_GatherVectorSByteSignExtendNonTemporal_Indices_long_long", ["Method"] = "GatherVectorSByteSignExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "SByte", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int64", ["ExtendedElementType"] = "SByte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt64()", ["AreOffsets"] = "false" }), + (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve2_GatherVectorSByteSignExtendNonTemporal_Indices_ulong_long", ["Method"] = "GatherVectorSByteSignExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "SByte", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int64", ["ExtendedElementType"] = "SByte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt64()", ["AreOffsets"] = "false" }), + (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve2_GatherVectorSByteSignExtendNonTemporal_Indices_long_ulong", ["Method"] = "GatherVectorSByteSignExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "SByte", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt64", ["ExtendedElementType"] = "SByte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt64()", ["AreOffsets"] = "false" }), + (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve2_GatherVectorSByteSignExtendNonTemporal_Indices_ulong_ulong", ["Method"] = "GatherVectorSByteSignExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "SByte", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt64", ["ExtendedElementType"] = "SByte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt64()", ["AreOffsets"] = "false" }), + + // (Templates.SveGatherVectorVectorBases, new Dictionary {["TestName"] = "Sve2_GatherVectorUInt16ZeroExtendNonTemporal_Bases_int_uint", ["Method"] = "GatherVectorUInt16ZeroExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt32", ["ExtendedElementType"] = "UInt16", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()" ["NextValueBase"] = "TestLibrary.Generator.GetInt32()}), + // (Templates.SveGatherVectorVectorBases, new Dictionary {["TestName"] = "Sve2_GatherVectorUInt16ZeroExtendNonTemporal_Bases_uint_uint", ["Method"] = "GatherVectorUInt16ZeroExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt32", ["ExtendedElementType"] = "UInt16", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()" ["NextValueBase"] = "TestLibrary.Generator.GetUInt32()}), + (Templates.SveGatherVectorVectorBases, new Dictionary {["TestName"] = "Sve2_GatherVectorUInt16ZeroExtendNonTemporal_Bases_long_ulong", ["Method"] = "GatherVectorUInt16ZeroExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt64", ["ExtendedElementType"] = "UInt16", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["NextValueBase"] = "TestLibrary.Generator.GetInt64()"}), + (Templates.SveGatherVectorVectorBases, new Dictionary {["TestName"] = "Sve2_GatherVectorUInt16ZeroExtendNonTemporal_Bases_ulong_ulong", ["Method"] = "GatherVectorUInt16ZeroExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt64", ["ExtendedElementType"] = "UInt16", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["NextValueBase"] = "TestLibrary.Generator.GetUInt64()"}), + (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve2_GatherVectorUInt16ZeroExtendNonTemporal_Indices_long_long", ["Method"] = "GatherVectorUInt16ZeroExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "UInt16", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int64", ["ExtendedElementType"] = "UInt16", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt64()", ["AreOffsets"] = "false"}), + (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve2_GatherVectorUInt16ZeroExtendNonTemporal_Indices_ulong_long", ["Method"] = "GatherVectorUInt16ZeroExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "UInt16", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int64", ["ExtendedElementType"] = "UInt16", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt64()", ["AreOffsets"] = "false"}), + (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve2_GatherVectorUInt16ZeroExtendNonTemporal_Indices_long_ulong", ["Method"] = "GatherVectorUInt16ZeroExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "UInt16", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt64", ["ExtendedElementType"] = "UInt16", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt64()", ["AreOffsets"] = "false"}), + (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve2_GatherVectorUInt16ZeroExtendNonTemporal_Indices_ulong_ulong", ["Method"] = "GatherVectorUInt16ZeroExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "UInt16", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt64", ["ExtendedElementType"] = "UInt16", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt64()", ["AreOffsets"] = "false"}), + + (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve2_GatherVectorUInt16WithByteOffsetsZeroExtendNonTemporal_int_uint", ["Method"] = "GatherVectorUInt16WithByteOffsetsZeroExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["Op2BaseType"] = "UInt16", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt32", ["ExtendedElementType"] = "UInt16", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["AreOffsets"] = "true"}), + (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve2_GatherVectorUInt16WithByteOffsetsZeroExtendNonTemporal_uint_uint", ["Method"] = "GatherVectorUInt16WithByteOffsetsZeroExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "UInt16", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt32", ["ExtendedElementType"] = "UInt16", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["AreOffsets"] = "true"}), + (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve2_GatherVectorUInt16WithByteOffsetsZeroExtendNonTemporal_long_long", ["Method"] = "GatherVectorUInt16WithByteOffsetsZeroExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "UInt16", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int64", ["ExtendedElementType"] = "UInt16", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt64()", ["AreOffsets"] = "true"}), + (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve2_GatherVectorUInt16WithByteOffsetsZeroExtendNonTemporal_ulong_long", ["Method"] = "GatherVectorUInt16WithByteOffsetsZeroExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "UInt16", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int64", ["ExtendedElementType"] = "UInt16", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt64()", ["AreOffsets"] = "true"}), + (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve2_GatherVectorUInt16WithByteOffsetsZeroExtendNonTemporal_long_ulong", ["Method"] = "GatherVectorUInt16WithByteOffsetsZeroExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "UInt16", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt64", ["ExtendedElementType"] = "UInt16", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt64()", ["AreOffsets"] = "true"}), + (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve2_GatherVectorUInt16WithByteOffsetsZeroExtendNonTemporal_ulong_ulong", ["Method"] = "GatherVectorUInt16WithByteOffsetsZeroExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "UInt16", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt64", ["ExtendedElementType"] = "UInt16", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt64()", ["AreOffsets"] = "true"}), + + (Templates.SveGatherVectorVectorBases, new Dictionary {["TestName"] = "Sve2_GatherVectorUInt32ZeroExtendNonTemporal_Bases_long_ulong", ["Method"] = "GatherVectorUInt32ZeroExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt64", ["ExtendedElementType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["NextValueBase"] = "TestLibrary.Generator.GetInt64()"}), + (Templates.SveGatherVectorVectorBases, new Dictionary {["TestName"] = "Sve2_GatherVectorUInt32ZeroExtendNonTemporal_Bases_ulong_ulong", ["Method"] = "GatherVectorUInt32ZeroExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt64", ["ExtendedElementType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["NextValueBase"] = "TestLibrary.Generator.GetUInt64()"}), + (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve2_GatherVectorUInt32ZeroExtendNonTemporal_Indices_long_long", ["Method"] = "GatherVectorUInt32ZeroExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int64", ["ExtendedElementType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt64()", ["AreOffsets"] = "false"}), + (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve2_GatherVectorUInt32ZeroExtendNonTemporal_Indices_ulong_long", ["Method"] = "GatherVectorUInt32ZeroExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int64", ["ExtendedElementType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt64()", ["AreOffsets"] = "false"}), + (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve2_GatherVectorUInt32ZeroExtendNonTemporal_Indices_long_ulong", ["Method"] = "GatherVectorUInt32ZeroExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt64", ["ExtendedElementType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt64()", ["AreOffsets"] = "false"}), + (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve2_GatherVectorUInt32ZeroExtendNonTemporal_Indices_ulong_ulong", ["Method"] = "GatherVectorUInt32ZeroExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt64", ["ExtendedElementType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt64()", ["AreOffsets"] = "false"}), + + (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve2_GatherVectorUInt32WithByteOffsetsZeroExtendNonTemporal_long_long", ["Method"] = "GatherVectorUInt32WithByteOffsetsZeroExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int64", ["ExtendedElementType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt64()", ["AreOffsets"] = "true"}), + (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve2_GatherVectorUInt32WithByteOffsetsZeroExtendNonTemporal_ulong_long", ["Method"] = "GatherVectorUInt32WithByteOffsetsZeroExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int64", ["ExtendedElementType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt64()", ["AreOffsets"] = "true"}), + (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve2_GatherVectorUInt32WithByteOffsetsZeroExtendNonTemporal_long_ulong", ["Method"] = "GatherVectorUInt32WithByteOffsetsZeroExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt64", ["ExtendedElementType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt64()", ["AreOffsets"] = "true"}), + (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve2_GatherVectorUInt32WithByteOffsetsZeroExtendNonTemporal_ulong_ulong", ["Method"] = "GatherVectorUInt32WithByteOffsetsZeroExtendNonTemporal", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt64", ["ExtendedElementType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt64()", ["AreOffsets"] = "true"}), + (Templates.SveVecTernOpTest, new Dictionary { ["TestName"] = "Sve2_InterleavingXorEvenOdd_byte", ["Method"] = "InterleavingXorEvenOdd", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Byte", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Byte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetByte()", ["ConvertFunc"] = "", ["ValidateIterResult"] = "result[i] != Helpers.InterleavingXorEvenOdd(firstOp, secondOp, thirdOp)[i]", ["GetIterResult"] = "Helpers.InterleavingXorEvenOdd(first, second, third)[i]"}), (Templates.SveVecTernOpTest, new Dictionary { ["TestName"] = "Sve2_InterleavingXorEvenOdd_short", ["Method"] = "InterleavingXorEvenOdd", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Int16", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int16", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt16()", ["ConvertFunc"] = "", ["ValidateIterResult"] = "result[i] != Helpers.InterleavingXorEvenOdd(firstOp, secondOp, thirdOp)[i]", ["GetIterResult"] = "Helpers.InterleavingXorEvenOdd(first, second, third)[i]"}), (Templates.SveVecTernOpTest, new Dictionary { ["TestName"] = "Sve2_InterleavingXorEvenOdd_int", ["Method"] = "InterleavingXorEvenOdd", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Int32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt32()", ["ConvertFunc"] = "", ["ValidateIterResult"] = "result[i] != Helpers.InterleavingXorEvenOdd(firstOp, secondOp, thirdOp)[i]", ["GetIterResult"] = "Helpers.InterleavingXorEvenOdd(first, second, third)[i]"}), diff --git a/src/tests/Common/GenerateHWIntrinsicTests/Arm/SveTests.cs b/src/tests/Common/GenerateHWIntrinsicTests/Arm/SveTests.cs index a646a4603193e4..a596fac36c5ded 100644 --- a/src/tests/Common/GenerateHWIntrinsicTests/Arm/SveTests.cs +++ b/src/tests/Common/GenerateHWIntrinsicTests/Arm/SveTests.cs @@ -620,26 +620,16 @@ static class SveTests (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve_GatherVectorUInt16ZeroExtend_Indices_ulong_ulong", ["Method"] = "GatherVectorUInt16ZeroExtend", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "UInt16", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt64", ["ExtendedElementType"] = "UInt16", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt64()", ["AreOffsets"] = "false" }), (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve_GatherVectorUInt32WithByteOffsetsZeroExtend_Offsets_long_long", ["Method"] = "GatherVectorUInt32WithByteOffsetsZeroExtend", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int64", ["ExtendedElementType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt64()", ["AreOffsets"] = "true" }), - (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve_GatherVectorUInt32WithByteOffsetsZeroExtend_Offsets_int_int", ["Method"] = "GatherVectorUInt32WithByteOffsetsZeroExtend", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int32", ["ExtendedElementType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt32()", ["AreOffsets"] = "true" }), (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve_GatherVectorUInt32WithByteOffsetsZeroExtend_Offsets_ulong_long", ["Method"] = "GatherVectorUInt32WithByteOffsetsZeroExtend", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int64", ["ExtendedElementType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt64()", ["AreOffsets"] = "true" }), - (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve_GatherVectorUInt32WithByteOffsetsZeroExtend_Offsets_uint_int", ["Method"] = "GatherVectorUInt32WithByteOffsetsZeroExtend", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int32", ["ExtendedElementType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt32()", ["AreOffsets"] = "true" }), (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve_GatherVectorUInt32WithByteOffsetsZeroExtend_Offsets_long_ulong", ["Method"] = "GatherVectorUInt32WithByteOffsetsZeroExtend", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt64", ["ExtendedElementType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt64()", ["AreOffsets"] = "true" }), - (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve_GatherVectorUInt32WithByteOffsetsZeroExtend_Offsets_int_uint", ["Method"] = "GatherVectorUInt32WithByteOffsetsZeroExtend", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt32", ["ExtendedElementType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["AreOffsets"] = "true" }), (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve_GatherVectorUInt32WithByteOffsetsZeroExtend_Offsets_ulong_ulong", ["Method"] = "GatherVectorUInt32WithByteOffsetsZeroExtend", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt64", ["ExtendedElementType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt64()", ["AreOffsets"] = "true" }), - (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve_GatherVectorUInt32WithByteOffsetsZeroExtend_Offsets_uint_uint", ["Method"] = "GatherVectorUInt32WithByteOffsetsZeroExtend", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt32", ["ExtendedElementType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["AreOffsets"] = "true" }), (Templates.SveGatherVectorVectorBases,new Dictionary {["TestName"] = "Sve_GatherVectorUInt32ZeroExtend_Bases_long_ulong", ["Method"] = "GatherVectorUInt32ZeroExtend", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt64", ["ExtendedElementType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["NextValueBase"] = "TestLibrary.Generator.GetInt64()",}), - // (Templates.SveGatherVectorVectorBases,new Dictionary {["TestName"] = "Sve_GatherVectorUInt32ZeroExtend_Bases_int_uint", ["Method"] = "GatherVectorUInt32ZeroExtend", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt32", ["ExtendedElementType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueBase"] = "TestLibrary.Generator.GetInt32()"}), (Templates.SveGatherVectorVectorBases,new Dictionary {["TestName"] = "Sve_GatherVectorUInt32ZeroExtend_Bases_ulong_ulong", ["Method"] = "GatherVectorUInt32ZeroExtend", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt64", ["ExtendedElementType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["NextValueBase"] = "TestLibrary.Generator.GetUInt64()"}), - // (Templates.SveGatherVectorVectorBases,new Dictionary {["TestName"] = "Sve_GatherVectorUInt32ZeroExtend_Bases_uint_uint", ["Method"] = "GatherVectorUInt32ZeroExtend", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt32", ["ExtendedElementType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueBase"] = "TestLibrary.Generator.GetUInt32()}), (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve_GatherVectorUInt32ZeroExtend_Indices_long_long", ["Method"] = "GatherVectorUInt32ZeroExtend", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int64", ["ExtendedElementType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt64()", ["AreOffsets"] = "false" }), - (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve_GatherVectorUInt32ZeroExtend_Indices_int_int", ["Method"] = "GatherVectorUInt32ZeroExtend", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int32", ["ExtendedElementType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt32()", ["AreOffsets"] = "false" }), (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve_GatherVectorUInt32ZeroExtend_Indices_ulong_long", ["Method"] = "GatherVectorUInt32ZeroExtend", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int64", ["ExtendedElementType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt64()", ["AreOffsets"] = "false" }), - (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve_GatherVectorUInt32ZeroExtend_Indices_uint_int", ["Method"] = "GatherVectorUInt32ZeroExtend", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int32", ["ExtendedElementType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt32()", ["AreOffsets"] = "false" }), (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve_GatherVectorUInt32ZeroExtend_Indices_long_ulong", ["Method"] = "GatherVectorUInt32ZeroExtend", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt64", ["ExtendedElementType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt64()", ["AreOffsets"] = "false" }), - (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve_GatherVectorUInt32ZeroExtend_Indices_int_uint", ["Method"] = "GatherVectorUInt32ZeroExtend", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt32", ["ExtendedElementType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["AreOffsets"] = "false" }), (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve_GatherVectorUInt32ZeroExtend_Indices_ulong_ulong", ["Method"] = "GatherVectorUInt32ZeroExtend", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt64", ["ExtendedElementType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt64()", ["AreOffsets"] = "false" }), - (Templates.SveGatherVector, new Dictionary {["TestName"] = "Sve_GatherVectorUInt32ZeroExtend_Indices_uint_uint", ["Method"] = "GatherVectorUInt32ZeroExtend", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt32", ["ExtendedElementType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["AreOffsets"] = "false" }), (Templates.SveGatherVectorFirstFaultingVectorBases, new Dictionary {["TestName"] = "Sve_GatherVectorFirstFaulting_Bases_double_ulong", ["Method"] = "GatherVectorFirstFaulting", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt64", ["ExtendedElementType"] = "Double", ["GetFfrType"] = "UInt64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["NextValueBase"] = "TestLibrary.Generator.GetDouble()"}), (Templates.SveGatherVectorFirstFaultingVectorBases, new Dictionary {["TestName"] = "Sve_GatherVectorFirstFaulting_Bases_long_ulong", ["Method"] = "GatherVectorFirstFaulting", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt64", ["ExtendedElementType"] = "Int64", ["GetFfrType"] = "UInt64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["NextValueBase"] = "TestLibrary.Generator.GetInt64()"}), @@ -714,20 +704,12 @@ static class SveTests (Templates.SveGatherVectorFirstFaulting, new Dictionary { ["TestName"] = "Sve_GatherVectorUInt16ZeroExtendFirstFaulting_Indices_uint_uint", ["Method"] = "GatherVectorUInt16ZeroExtendFirstFaulting", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "UInt16", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt32", ["ExtendedElementType"] = "UInt16", ["GetFfrType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["AreOffsets"] = "false" }), (Templates.SveGatherVectorFirstFaulting, new Dictionary { ["TestName"] = "Sve_GatherVectorUInt16ZeroExtendFirstFaulting_Indices_ulong_long", ["Method"] = "GatherVectorUInt16ZeroExtendFirstFaulting", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "UInt16", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int64", ["ExtendedElementType"] = "UInt16", ["GetFfrType"] = "UInt64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt64()", ["AreOffsets"] = "false" }), (Templates.SveGatherVectorFirstFaulting, new Dictionary { ["TestName"] = "Sve_GatherVectorUInt16ZeroExtendFirstFaulting_Indices_ulong_ulong", ["Method"] = "GatherVectorUInt16ZeroExtendFirstFaulting", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "UInt16", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt64", ["ExtendedElementType"] = "UInt16", ["GetFfrType"] = "UInt64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt64()", ["AreOffsets"] = "false" }), - (Templates.SveGatherVectorByteOffsetFirstFaulting, new Dictionary { ["TestName"] = "Sve_GatherVectorUInt32WithByteOffsetsZeroExtendFirstFaulting_offsets_int_int", ["Method"] = "GatherVectorUInt32WithByteOffsetsZeroExtendFirstFaulting", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int32", ["GetFfrType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt32()", ["ConvertFunc"] = "(UInt32)"}), - (Templates.SveGatherVectorByteOffsetFirstFaulting, new Dictionary { ["TestName"] = "Sve_GatherVectorUInt32WithByteOffsetsZeroExtendFirstFaulting_offsets_int_uint", ["Method"] = "GatherVectorUInt32WithByteOffsetsZeroExtendFirstFaulting", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt32", ["GetFfrType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["ConvertFunc"] = "(UInt32)"}), (Templates.SveGatherVectorByteOffsetFirstFaulting, new Dictionary { ["TestName"] = "Sve_GatherVectorUInt32WithByteOffsetsZeroExtendFirstFaulting_offsets_long_long", ["Method"] = "GatherVectorUInt32WithByteOffsetsZeroExtendFirstFaulting", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int64", ["GetFfrType"] = "UInt64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt64()", ["ConvertFunc"] = "(UInt32)"}), (Templates.SveGatherVectorByteOffsetFirstFaulting, new Dictionary { ["TestName"] = "Sve_GatherVectorUInt32WithByteOffsetsZeroExtendFirstFaulting_offsets_long_ulong", ["Method"] = "GatherVectorUInt32WithByteOffsetsZeroExtendFirstFaulting", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt64", ["GetFfrType"] = "UInt64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt64()", ["ConvertFunc"] = "(UInt32)"}), - (Templates.SveGatherVectorByteOffsetFirstFaulting, new Dictionary { ["TestName"] = "Sve_GatherVectorUInt32WithByteOffsetsZeroExtendFirstFaulting_offsets_uint_int", ["Method"] = "GatherVectorUInt32WithByteOffsetsZeroExtendFirstFaulting", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int32", ["GetFfrType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt32()", ["ConvertFunc"] = "(UInt32)"}), - (Templates.SveGatherVectorByteOffsetFirstFaulting, new Dictionary { ["TestName"] = "Sve_GatherVectorUInt32WithByteOffsetsZeroExtendFirstFaulting_offsets_uint_uint", ["Method"] = "GatherVectorUInt32WithByteOffsetsZeroExtendFirstFaulting", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt32", ["GetFfrType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["ConvertFunc"] = "(UInt32)"}), (Templates.SveGatherVectorByteOffsetFirstFaulting, new Dictionary { ["TestName"] = "Sve_GatherVectorUInt32WithByteOffsetsZeroExtendFirstFaulting_offsets_ulong_long", ["Method"] = "GatherVectorUInt32WithByteOffsetsZeroExtendFirstFaulting", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int64", ["GetFfrType"] = "UInt64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt64()", ["ConvertFunc"] = "(UInt32)"}), (Templates.SveGatherVectorByteOffsetFirstFaulting, new Dictionary { ["TestName"] = "Sve_GatherVectorUInt32WithByteOffsetsZeroExtendFirstFaulting_offsets_ulong_ulong", ["Method"] = "GatherVectorUInt32WithByteOffsetsZeroExtendFirstFaulting", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt64", ["GetFfrType"] = "UInt64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt64()", ["ConvertFunc"] = "(UInt32)"}), - (Templates.SveGatherVectorFirstFaulting, new Dictionary { ["TestName"] = "Sve_GatherVectorUInt32ZeroExtendFirstFaulting_Indices_int_int", ["Method"] = "GatherVectorUInt32ZeroExtendFirstFaulting", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int32", ["ExtendedElementType"] = "UInt32", ["GetFfrType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt32()", ["AreOffsets"] = "false" }), - (Templates.SveGatherVectorFirstFaulting, new Dictionary { ["TestName"] = "Sve_GatherVectorUInt32ZeroExtendFirstFaulting_Indices_int_uint", ["Method"] = "GatherVectorUInt32ZeroExtendFirstFaulting", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt32", ["ExtendedElementType"] = "UInt32", ["GetFfrType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["AreOffsets"] = "false" }), (Templates.SveGatherVectorFirstFaulting, new Dictionary { ["TestName"] = "Sve_GatherVectorUInt32ZeroExtendFirstFaulting_Indices_long_long", ["Method"] = "GatherVectorUInt32ZeroExtendFirstFaulting", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int64", ["ExtendedElementType"] = "UInt32", ["GetFfrType"] = "UInt64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt64()", ["AreOffsets"] = "false" }), (Templates.SveGatherVectorFirstFaulting, new Dictionary { ["TestName"] = "Sve_GatherVectorUInt32ZeroExtendFirstFaulting_Indices_long_ulong", ["Method"] = "GatherVectorUInt32ZeroExtendFirstFaulting", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt64", ["ExtendedElementType"] = "UInt32", ["GetFfrType"] = "UInt64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt64()", ["AreOffsets"] = "false" }), - (Templates.SveGatherVectorFirstFaulting, new Dictionary { ["TestName"] = "Sve_GatherVectorUInt32ZeroExtendFirstFaulting_Indices_uint_int", ["Method"] = "GatherVectorUInt32ZeroExtendFirstFaulting", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int32", ["ExtendedElementType"] = "UInt32", ["GetFfrType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt32()", ["AreOffsets"] = "false" }), - (Templates.SveGatherVectorFirstFaulting, new Dictionary { ["TestName"] = "Sve_GatherVectorUInt32ZeroExtendFirstFaulting_Indices_uint_uint", ["Method"] = "GatherVectorUInt32ZeroExtendFirstFaulting", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt32", ["ExtendedElementType"] = "UInt32", ["GetFfrType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["AreOffsets"] = "false" }), (Templates.SveGatherVectorFirstFaulting, new Dictionary { ["TestName"] = "Sve_GatherVectorUInt32ZeroExtendFirstFaulting_Indices_ulong_long", ["Method"] = "GatherVectorUInt32ZeroExtendFirstFaulting", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int64", ["ExtendedElementType"] = "UInt32", ["GetFfrType"] = "UInt64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt64()", ["AreOffsets"] = "false" }), (Templates.SveGatherVectorFirstFaulting, new Dictionary { ["TestName"] = "Sve_GatherVectorUInt32ZeroExtendFirstFaulting_Indices_ulong_ulong", ["Method"] = "GatherVectorUInt32ZeroExtendFirstFaulting", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt64", ["ExtendedElementType"] = "UInt32", ["GetFfrType"] = "UInt64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "Helpers.getMaskUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt64()", ["AreOffsets"] = "false" }), diff --git a/src/tests/GC/Regressions/Github/Runtime_76219/Runtime_76219.csproj b/src/tests/GC/Regressions/Github/Runtime_76219/Runtime_76219.csproj index aefac61c542f2b..657d4ca65cbad7 100644 --- a/src/tests/GC/Regressions/Github/Runtime_76219/Runtime_76219.csproj +++ b/src/tests/GC/Regressions/Github/Runtime_76219/Runtime_76219.csproj @@ -5,6 +5,9 @@ True 1 + + + true diff --git a/src/tests/JIT/Methodical/Boxing/morph/sin3double.il b/src/tests/JIT/Methodical/Boxing/morph/sin3double.il index aaf4fd9619f17f..dbe6d04d3707bd 100644 --- a/src/tests/JIT/Methodical/Boxing/morph/sin3double.il +++ b/src/tests/JIT/Methodical/Boxing/morph/sin3double.il @@ -14,7 +14,6 @@ } .assembly extern xunit.core {} .assembly extern Microsoft.DotNet.XUnitExtensions { .publickeytoken = (31 BF 38 56 AD 36 4E 35 ) } -.assembly extern TestLibrary { .ver 0:0:0:0 } .namespace Test_sin3double { .class private sequential ansi sealed beforefieldinit VV extends [mscorlib]System.ValueType @@ -204,11 +203,6 @@ 01 00 00 00 ) .custom instance void [Microsoft.DotNet.XUnitExtensions]Xunit.ActiveIssueAttribute::.ctor(string, valuetype [Microsoft.DotNet.XUnitExtensions]Xunit.TestRuntimes) = {string('https://github.com/dotnet/runtime/issues/34196') int32(2)} - .custom instance void [Microsoft.DotNet.XUnitExtensions]Xunit.ActiveIssueAttribute::.ctor(string, class [mscorlib]System.Type, string[]) = { - string('https://github.com/dotnet/runtime/issues/124222') - type([TestLibrary]TestLibrary.PlatformDetection) - string[1] ('IsWasm') - } .entrypoint .locals (int32 V_0, float64 V_1, diff --git a/src/tests/JIT/Methodical/flowgraph/bug619534/moduleHandleCache.cs b/src/tests/JIT/Methodical/flowgraph/bug619534/moduleHandleCache.cs index 29ad67b52dc838..207cc2b205c0e3 100644 --- a/src/tests/JIT/Methodical/flowgraph/bug619534/moduleHandleCache.cs +++ b/src/tests/JIT/Methodical/flowgraph/bug619534/moduleHandleCache.cs @@ -23,7 +23,6 @@ at Repro.Main() in c:\tests\Dev10\640711\app.cs:line 16 using System; using System.Runtime.CompilerServices; -using TestLibrary; using Xunit; namespace Test_moduleHandleCache_cs @@ -42,7 +41,6 @@ static void Caller(bool b) } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/124222", typeof(PlatformDetection), nameof(PlatformDetection.IsWasm))] public static void TestEntryPoint() { try diff --git a/src/tests/JIT/Methodical/switch/switch6.il b/src/tests/JIT/Methodical/switch/switch6.il index 89bfeed2aa1818..898b185fb4152b 100644 --- a/src/tests/JIT/Methodical/switch/switch6.il +++ b/src/tests/JIT/Methodical/switch/switch6.il @@ -6,8 +6,6 @@ .assembly extern System.Runtime.Extensions { auto } .assembly extern legacy library mscorlib { auto } .assembly extern System.Console { auto } -.assembly extern Microsoft.DotNet.XUnitExtensions { .publickeytoken = (31 BF 38 56 AD 36 4E 35 ) } -.assembly extern TestLibrary { .ver 0:0:0:0 } .assembly 'switch6' { @@ -89,11 +87,6 @@ .custom instance void [xunit.core]Xunit.FactAttribute::.ctor() = ( 01 00 00 00 ) - .custom instance void [Microsoft.DotNet.XUnitExtensions]Xunit.ActiveIssueAttribute::.ctor(string, class [mscorlib]System.Type, string[]) = { - string('https://github.com/dotnet/runtime/issues/124222') - type([TestLibrary]TestLibrary.PlatformDetection) - string[1] ('IsWasm') - } .entrypoint .maxstack 8 IL_0000: ldc.i4.1 diff --git a/src/tests/JIT/opt/InstructionCombining/Casts.cs b/src/tests/JIT/opt/InstructionCombining/Casts.cs new file mode 100644 index 00000000000000..438b4869b3ccf5 --- /dev/null +++ b/src/tests/JIT/opt/InstructionCombining/Casts.cs @@ -0,0 +1,694 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Runtime.CompilerServices; +using Xunit; + +namespace TestMultipleCasts +{ + public class Program + { + [MethodImpl(MethodImplOptions.NoInlining)] + [Fact] + public static int CheckMultipleCasts() + { + bool fail = false; + + // Cast int -> x + if (CastIntSbyte(0x11223344) != 0x44) + { + fail = true; + } + if (CastIntShort(-0x11223344) != -0x3344) + { + fail = true; + } + if (CastIntLong(0x11223344) != 0x11223344) + { + fail = true; + } + + // Cast long -> x + if (CastLongSbyte(0xFFEEDDCCBBAAL) != -0x56) + { + fail = true; + } + if (CastLongShort(0xFFEEDDCCBBAAL) != -0x4456) + { + fail = true; + } + if (CastLongInt(0xFFEEDDCCBBAAL) != -0x22334456) + { + fail = true; + } + + // Cast uint -> x + if (CastUIntByte(0x11223344u) != 0x44) + { + fail = true; + } + if (CastUIntUShort(0x11223344u) != 0x3344) + { + fail = true; + } + if (CastUIntULong(0x11223344u) != 0x11223344ul) + { + fail = true; + } + + // Cast ulong -> x + if (CastULongByte(0xFFEEDDCCBBAAul) != 0xAA) + { + fail = true; + } + if (CastULongUShort(0xFFEEDDCCBBAAul) != 0xBBAA) + { + fail = true; + } + if (CastULongUInt(0xFFEEDDCCBBAAul) != 0xDDCCBBAAu) + { + fail = true; + } + + // Cast int -> x -> int + if (CastIntSbyteInt(0xF0) != -0x10) + { + fail = true; + } + if (CastIntShortInt(0xFF8001) != -0x7FFF) + { + fail = true; + } + if (CastIntLongInt(0x11223344) != 0x11223344) + { + fail = true; + } + + // Cast int -> x -> long + if (CastIntSbyteLong(0x12345678) != 0x78) + { + fail = true; + } + if (CastIntShortLong(0x12345678) != 0x5678) + { + fail = true; + } + + // Cast long -> x -> int + if (CastLongSbyteInt(0xA7L) != -0x59) + { + fail = true; + } + if (CastLongShortInt(0xFFFFFFFF8003L) != -0x7FFD) + { + fail = true; + } + + // Cast long -> x -> long + if (CastLongSbyteLong(0xFEL) != -0x2L) + { + fail = true; + } + if (CastLongShortLong(0xDEADL) != -0x2153L) + { + fail = true; + } + if (CastLongIntLong(0x1ABCDEF00L) != -0x54321100L) + { + fail = true; + } + + // Cast uint -> x -> uint + if (CastUIntByteUInt(0xF0u) != 0xF0u) + { + fail = true; + } + if (CastUIntUShortUInt(0xFF8001u) != 0x8001u) + { + fail = true; + } + + // Cast uint -> x -> ulong + if (CastUIntByteULong(0x12345678u) != 0x78ul) + { + fail = true; + } + if (CastUIntUShortULong(0x12345678u) != 0x5678ul) + { + fail = true; + } + if (CastUIntULongUInt(0x11223344u) != 0x11223344u) + { + fail = true; + } + + // Cast ulong -> x -> uint + if (CastULongByteUInt(0xA7ul) != 0xA7u) + { + fail = true; + } + if (CastULongUShortUInt(0xFFFFFFFF8003ul) != 0x8003u) + { + fail = true; + } + + // Cast ulong -> x -> ulong + if (CastULongByteULong(0xFEul) != 0xFEul) + { + fail = true; + } + if (CastULongUShortULong(0xDEADul) != 0xDEADul) + { + fail = true; + } + if (CastULongUIntULong(0x1ABCDEF00ul) != 0xABCDEF00ul) + { + fail = true; + } + + // Cast int -> long -> x + if (CastIntLongSbyte(0x11223344) != 0x44) + { + fail = true; + } + if (CastIntLongShort(0x11223344) != 0x3344) + { + fail = true; + } + + // Cast uint -> ulong -> x + if (CastUIntULongByte(0x11223344u) != 0x44) + { + fail = true; + } + if (CastUIntULongUShort(0x11223344u) != 0x3344) + { + fail = true; + } + + // Cast long -> int -> short -> sbyte + if (CastLongIntShortSByte(0x11223344) != 0x44) + { + fail = true; + } + + // Cast ulong -> uint -> ushort -> byte + if (CastULongUIntUShortByte(0x11223344u) != 0x44) + { + fail = true; + } + + // Cast sbyte -> short -> int -> long + if (CastSByteShortIntLong(-0x59) != -0x59L) + { + fail = true; + } + + // Cast byte -> ushort -> uint -> ulong + if (CastByteUShortUIntULong(0xA7) != 0xA7ul) + { + fail = true; + } + + // Cast int -> long -> int -> long + if (CastIntSByteIntSByte(-0x15263748) != -0x48) + { + fail = true; + } + if (CastIntShortIntShort(-0x15263748) != -0x3748) + { + fail = true; + } + if (CastIntLongIntLong(-0x15263748) != -0x15263748l) + { + fail = true; + } + + // Cast uint -> x -> uint -> x + if (CastUIntByteUIntByte(0xF0u) != 0xF0) + { + fail = true; + } + if (CastUIntUShortUIntUShort(0xFF8001u) != 0x8001) + { + fail = true; + } + if (CastUIntULongUIntULong(0x11223344u) != 0x11223344ul) + { + fail = true; + } + + // Cast long -> x -> long -> x + if (CastLongSByteLongSByte(0xA7L) != -0x59) + { + fail = true; + } + if (CastLongShortLongShort(0xFFFFFFFF8003L) != -0x7FFD) + { + fail = true; + } + if (CastLongIntLongInt(0x1ABCDEF00L) != -0x54321100) + { + fail = true; + } + + // Cast ulong -> x -> ulong -> x + if (CastULongByteULongByte(0xA7ul) != 0xA7) + { + fail = true; + } + if (CastULongUShortULongUShort(0xFFFFFFFF8003ul) != 0x8003) + { + fail = true; + } + if (CastULongUIntULongUInt(0x1ABCDEF00ul) != 0xABCDEF00u) + { + fail = true; + } + + if (fail) + { + return 101; + } + return 100; + } + + // Cast int -> x + + [MethodImpl(MethodImplOptions.NoInlining)] + static sbyte CastIntSbyte(int x) + { + //ARM64-FULL-LINE: sxtb {{w[0-9]+}}, {{w[0-9]+}} + return (sbyte)x; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static short CastIntShort(int x) + { + //ARM64-FULL-LINE: sxth {{w[0-9]+}}, {{w[0-9]+}} + return (short)x; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static long CastIntLong(int x) + { + //ARM64-FULL-LINE: sxtw {{x[0-9]+}}, {{w[0-9]+}} + return (long)x; + } + + // Cast long -> x + + [MethodImpl(MethodImplOptions.NoInlining)] + static sbyte CastLongSbyte(long x) + { + //ARM64-FULL-LINE: sxtb {{w[0-9]+}}, {{w[0-9]+}} + return (sbyte)x; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static short CastLongShort(long x) + { + //ARM64-FULL-LINE: sxth {{w[0-9]+}}, {{w[0-9]+}} + return (short)x; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static int CastLongInt(long x) + { + //ARM64-FULL-LINE: mov {{w[0-9]+}}, {{w[0-9]+}} + return (int)x; + } + + // Cast uint -> x + + [MethodImpl(MethodImplOptions.NoInlining)] + static byte CastUIntByte(uint x) + { + //ARM64-FULL-LINE: uxtb {{w[0-9]+}}, {{w[0-9]+}} + return (byte)x; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static ushort CastUIntUShort(uint x) + { + //ARM64-FULL-LINE: uxth {{w[0-9]+}}, {{w[0-9]+}} + return (ushort)x; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static ulong CastUIntULong(uint x) + { + //ARM64-FULL-LINE: mov {{w[0-9]+}}, {{w[0-9]+}} + return (ulong)x; + } + + // Cast ulong -> x + + [MethodImpl(MethodImplOptions.NoInlining)] + static byte CastULongByte(ulong x) + { + //ARM64-FULL-LINE: uxtb {{w[0-9]+}}, {{w[0-9]+}} + return (byte)x; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static ushort CastULongUShort(ulong x) + { + //ARM64-FULL-LINE: uxth {{w[0-9]+}}, {{w[0-9]+}} + return (ushort)x; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static uint CastULongUInt(ulong x) + { + //ARM64-FULL-LINE: mov {{w[0-9]+}}, {{w[0-9]+}} + return (uint)x; + } + + // Cast int -> x -> int + + [MethodImpl(MethodImplOptions.NoInlining)] + static int CastIntSbyteInt(int x) + { + //ARM64-FULL-LINE: sxtb {{w[0-9]+}}, {{w[0-9]+}} + return (sbyte)x; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static int CastIntShortInt(int x) + { + //ARM64-FULL-LINE: sxth {{w[0-9]+}}, {{w[0-9]+}} + return (short)x; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static int CastIntLongInt(int x) + { + //ARM64-NOT: sxtw {{x[0-9]+}}, {{w[0-9]+}} + return (int)(long)x; + } + + // Cast int -> x -> long + + [MethodImpl(MethodImplOptions.NoInlining)] + static long CastIntSbyteLong(int x) + { + //ARM64-FULL-LINE: sxtb {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: sxtw {{x[0-9]+}}, {{w[0-9]+}} + return (sbyte)x; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static long CastIntShortLong(int x) + { + //ARM64-FULL-LINE: sxth {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: sxtw {{x[0-9]+}}, {{w[0-9]+}} + return (short)x; + } + + // Cast long -> x -> int + + [MethodImpl(MethodImplOptions.NoInlining)] + static int CastLongSbyteInt(long x) + { + //ARM64-FULL-LINE: sxtb {{w[0-9]+}}, {{w[0-9]+}} + return (sbyte)x; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static int CastLongShortInt(long x) + { + //ARM64-FULL-LINE: sxth {{w[0-9]+}}, {{w[0-9]+}} + return (short)x; + } + + // Cast long -> x -> long + + [MethodImpl(MethodImplOptions.NoInlining)] + static long CastLongSbyteLong(long x) + { + //ARM64-FULL-LINE: sxtb {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: sxtw {{x[0-9]+}}, {{w[0-9]+}} + return (sbyte)x; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static long CastLongShortLong(long x) + { + //ARM64-FULL-LINE: sxth {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: sxtw {{x[0-9]+}}, {{w[0-9]+}} + return (short)x; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static long CastLongIntLong(long x) + { + //ARM64-FULL-LINE: sxtw {{x[0-9]+}}, {{w[0-9]+}} + return (int)x; + } + + // Cast uint -> x -> uint + + [MethodImpl(MethodImplOptions.NoInlining)] + static uint CastUIntByteUInt(uint x) + { + //ARM64-FULL-LINE: uxtb {{w[0-9]+}}, {{w[0-9]+}} + return (byte)x; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static uint CastUIntUShortUInt(uint x) + { + //ARM64-FULL-LINE: uxth {{w[0-9]+}}, {{w[0-9]+}} + return (ushort)x; + } + + // Cast uint -> x -> ulong + + [MethodImpl(MethodImplOptions.NoInlining)] + static ulong CastUIntByteULong(uint x) + { + //ARM64-FULL-LINE: uxtb {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: mov {{w[0-9]+}}, {{w[0-9]+}} + return (byte)x; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static ulong CastUIntUShortULong(uint x) + { + //ARM64-FULL-LINE: uxth {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: mov {{w[0-9]+}}, {{w[0-9]+}} + return (ushort)x; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static uint CastUIntULongUInt(uint x) + { + //ARM64-FULL-LINE: mov {{w[0-9]+}}, {{w[0-9]+}} + return (uint)(ulong)x; + } + + // Cast ulong -> x -> uint + + [MethodImpl(MethodImplOptions.NoInlining)] + static uint CastULongByteUInt(ulong x) + { + //ARM64-FULL-LINE: uxtb {{w[0-9]+}}, {{w[0-9]+}} + return (byte)x; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static uint CastULongUShortUInt(ulong x) + { + //ARM64-FULL-LINE: uxth {{w[0-9]+}}, {{w[0-9]+}} + return (ushort)x; + } + + // Cast ulong -> x -> ulong + + [MethodImpl(MethodImplOptions.NoInlining)] + static ulong CastULongByteULong(ulong x) + { + //ARM64-FULL-LINE: uxtb {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: mov {{w[0-9]+}}, {{w[0-9]+}} + return (byte)x; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static ulong CastULongUShortULong(ulong x) + { + //ARM64-FULL-LINE: uxth {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: mov {{w[0-9]+}}, {{w[0-9]+}} + return (ushort)x; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static ulong CastULongUIntULong(ulong x) + { + //ARM64-FULL-LINE: mov {{w[0-9]+}}, {{w[0-9]+}} + return (uint)x; + } + + // Cast int -> long -> x + + [MethodImpl(MethodImplOptions.NoInlining)] + static sbyte CastIntLongSbyte(int x) + { + //ARM64-FULL-LINE: sxtb {{w[0-9]+}}, {{w[0-9]+}} + return (sbyte)(long)x; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static short CastIntLongShort(int x) + { + //ARM64-FULL-LINE: sxth {{w[0-9]+}}, {{w[0-9]+}} + return (short)(long)x; + } + + // Cast uint -> ulong -> x + + [MethodImpl(MethodImplOptions.NoInlining)] + static byte CastUIntULongByte(uint x) + { + //ARM64-FULL-LINE: uxtb {{w[0-9]+}}, {{w[0-9]+}} + return (byte)(ulong)x; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static ushort CastUIntULongUShort(uint x) + { + //ARM64-FULL-LINE: uxth {{w[0-9]+}}, {{w[0-9]+}} + return (ushort)(ulong)x; + } + + // Cast long -> int -> short -> sbyte + + [MethodImpl(MethodImplOptions.NoInlining)] + static sbyte CastLongIntShortSByte(long x) + { + //ARM64-FULL-LINE: sxtb {{w[0-9]+}}, {{w[0-9]+}} + return (sbyte)(short)(int)x; + } + + // Cast ulong -> uint -> ushort -> byte + + [MethodImpl(MethodImplOptions.NoInlining)] + static byte CastULongUIntUShortByte(ulong x) + { + //ARM64-FULL-LINE: uxtb {{w[0-9]+}}, {{w[0-9]+}} + return (byte)(ushort)(uint)x; + } + + // Cast sbyte -> short -> int -> long + + [MethodImpl(MethodImplOptions.NoInlining)] + static long CastSByteShortIntLong(sbyte x) + { + //ARM64-FULL-LINE: sxtb {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: sxtw {{x[0-9]+}}, {{w[0-9]+}} + return (long)(int)(short)x; + } + + // Cast byte -> ushort -> uint -> ulong + + [MethodImpl(MethodImplOptions.NoInlining)] + static ulong CastByteUShortUIntULong(byte x) + { + //ARM64-FULL-LINE: uxtb {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: mov {{w[0-9]+}}, {{w[0-9]+}} + return (ulong)(uint)(ushort)x; + } + + // Cast int -> x -> int -> x + + [MethodImpl(MethodImplOptions.NoInlining)] + static sbyte CastIntSByteIntSByte(int x) + { + //ARM64-FULL-LINE: sxtb {{w[0-9]+}}, {{w[0-9]+}} + return (sbyte)(int)(sbyte)x; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static short CastIntShortIntShort(int x) + { + //ARM64-FULL-LINE: sxth {{w[0-9]+}}, {{w[0-9]+}} + return (short)(int)(short)x; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static long CastIntLongIntLong(int x) + { + //ARM64-FULL-LINE: sxtw {{x[0-9]+}}, {{w[0-9]+}} + return (long)(int)(long)x; + } + + // Cast uint -> x -> uint -> x + + [MethodImpl(MethodImplOptions.NoInlining)] + static byte CastUIntByteUIntByte(uint x) + { + //ARM64-FULL-LINE: uxtb {{w[0-9]+}}, {{w[0-9]+}} + return (byte)(uint)(byte)x; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static ushort CastUIntUShortUIntUShort(uint x) + { + //ARM64-FULL-LINE: uxth {{w[0-9]+}}, {{w[0-9]+}} + return (ushort)(uint)(ushort)x; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static ulong CastUIntULongUIntULong(uint x) + { + //ARM64-FULL-LINE: mov {{w[0-9]+}}, {{w[0-9]+}} + return (ulong)(uint)(ulong)x; + } + + // Cast long -> x -> long -> x + + [MethodImpl(MethodImplOptions.NoInlining)] + static sbyte CastLongSByteLongSByte(long x) + { + //ARM64-FULL-LINE: sxtb {{w[0-9]+}}, {{w[0-9]+}} + return (sbyte)(long)(sbyte)x; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static short CastLongShortLongShort(long x) + { + //ARM64-FULL-LINE: sxth {{w[0-9]+}}, {{w[0-9]+}} + return (short)(long)(short)x; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static int CastLongIntLongInt(long x) + { + //ARM64-FULL-LINE: mov {{w[0-9]+}}, {{w[0-9]+}} + return (int)(long)(int)x; + } + + // Cast ulong -> x -> ulong -> x + + [MethodImpl(MethodImplOptions.NoInlining)] + static byte CastULongByteULongByte(ulong x) + { + //ARM64-FULL-LINE: uxtb {{w[0-9]+}}, {{w[0-9]+}} + return (byte)(ulong)(byte)x; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static ushort CastULongUShortULongUShort(ulong x) + { + //ARM64-FULL-LINE: uxth {{w[0-9]+}}, {{w[0-9]+}} + return (ushort)(ulong)(ushort)x; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static uint CastULongUIntULongUInt(ulong x) + { + //ARM64-FULL-LINE: mov {{w[0-9]+}}, {{w[0-9]+}} + return (uint)(ulong)(uint)x; + } + } +} diff --git a/src/tests/JIT/opt/InstructionCombining/Casts.csproj b/src/tests/JIT/opt/InstructionCombining/Casts.csproj new file mode 100644 index 00000000000000..b3cc1eeece28c6 --- /dev/null +++ b/src/tests/JIT/opt/InstructionCombining/Casts.csproj @@ -0,0 +1,17 @@ + + + + true + + + None + True + + + + true + + + + + diff --git a/src/tests/nativeaot/Directory.Build.props b/src/tests/nativeaot/Directory.Build.props index 1e08092b2bc7f1..17342717f61c8e 100644 --- a/src/tests/nativeaot/Directory.Build.props +++ b/src/tests/nativeaot/Directory.Build.props @@ -5,11 +5,5 @@ true - - - true diff --git a/src/tests/nativeaot/Directory.Build.targets b/src/tests/nativeaot/Directory.Build.targets deleted file mode 100644 index ba8535b823ebf5..00000000000000 --- a/src/tests/nativeaot/Directory.Build.targets +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - diff --git a/src/tests/nativeaot/MobileSmokeTest/MobileSmokeTest.cs b/src/tests/nativeaot/MobileSmokeTest/MobileSmokeTest.cs new file mode 100644 index 00000000000000..2297d5641251ec --- /dev/null +++ b/src/tests/nativeaot/MobileSmokeTest/MobileSmokeTest.cs @@ -0,0 +1,28 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.CompilerServices; + +unsafe class Program +{ + [MethodImpl(MethodImplOptions.NoInlining)] + static int ReadPointer(int* pVal) + { + return *pVal; + } + + static int Main() + { + try + { + ReadPointer(null); + } + catch (Exception) + { + return 100; + } + + return 1; + } +} diff --git a/src/tests/nativeaot/MobileSmokeTest/MobileSmokeTest.csproj b/src/tests/nativeaot/MobileSmokeTest/MobileSmokeTest.csproj new file mode 100644 index 00000000000000..fe1da589c74ba1 --- /dev/null +++ b/src/tests/nativeaot/MobileSmokeTest/MobileSmokeTest.csproj @@ -0,0 +1,14 @@ + + + Exe + false + true + true + + + + + + + + diff --git a/src/tests/nativeaot/StartupHook/StartupHook.csproj b/src/tests/nativeaot/StartupHook/StartupHook.csproj index 046dce277364a3..ed6e89a9fc27db 100644 --- a/src/tests/nativeaot/StartupHook/StartupHook.csproj +++ b/src/tests/nativeaot/StartupHook/StartupHook.csproj @@ -5,8 +5,8 @@ true true $(NoWarn);IL2026 + true false - true diff --git a/src/tests/nativeaot/nativeaot.csproj b/src/tests/nativeaot/nativeaot.csproj new file mode 100644 index 00000000000000..21db07dd33d756 --- /dev/null +++ b/src/tests/nativeaot/nativeaot.csproj @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/TestFrameworkTests.g.cs b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/TestFrameworkTests.g.cs index 9a3a6d49cd8492..3d62106f5cbe2e 100644 --- a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/TestFrameworkTests.g.cs +++ b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/TestFrameworkTests.g.cs @@ -93,6 +93,18 @@ public Task VerifyDefineAttributeBehavior() return RunTest(allowMissingWarnings: true); } + [Fact] + public Task VerifyKeptAttributeAttributeWorks() + { + return RunTest(allowMissingWarnings: true); + } + + [Fact] + public Task VerifyLocalsAreChanged() + { + return RunTest(allowMissingWarnings: true); + } + [Fact] public Task VerifyResourceInAssemblyAttributesBehavior() { diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptAttributeAttribute.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptAttributeAttribute.cs index b07a1c0a96a928..c8f50eb4af4962 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptAttributeAttribute.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptAttributeAttribute.cs @@ -19,5 +19,18 @@ public KeptAttributeAttribute(Type type) { ArgumentNullException.ThrowIfNull(type); } + + /// + /// Use this constructor when you want to explicitly verify that an attribute with specific parameters survived. + /// + /// This is useful when you have a test that has multiple attributes of the same type but passed each is passed different parameters + /// and you want to verify which one(s) survived + /// + /// + /// + public KeptAttributeAttribute(Type type, params object[] args) + { + ArgumentNullException.ThrowIfNull(type); + } } } diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/TypeMap.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/TypeMap.cs index 558306f20960eb..56867194edec4c 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/TypeMap.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/TypeMap.cs @@ -14,11 +14,6 @@ using Mono.Linker.Tests.Cases.Reflection.Dependencies; using Mono.Linker.Tests.Cases.Reflection.Dependencies.Library; -[assembly: KeptAttributeAttribute(typeof(TypeMapAttribute))] -[assembly: KeptAttributeAttribute(typeof(TypeMapAssociationAttribute))] -[assembly: KeptAttributeAttribute(typeof(TypeMapAssociationAttribute))] -[assembly: KeptAttributeAttribute(typeof(TypeMapAttribute))] -[assembly: KeptAttributeAttribute(typeof(TypeMapAttribute))] [assembly: TypeMap("TrimTargetIsTarget", typeof(TargetAndTrimTarget), typeof(TargetAndTrimTarget))] [assembly: TypeMap("TrimTargetIsUnrelated", typeof(TargetType), typeof(TrimTarget))] [assembly: TypeMap(nameof(AllocatedNoTypeCheckClassTarget), typeof(AllocatedNoTypeCheckClassTarget), typeof(AllocatedNoTypeCheckClass))] @@ -33,14 +28,29 @@ [assembly: TypeMap("Ldobj", typeof(LdobjTarget), typeof(LdobjType))] [assembly: TypeMap("ArrayElement", typeof(ArrayElementTarget), typeof(ArrayElement))] [assembly: TypeMap("TrimTargetIsAllocatedNoTypeCheckNoBoxStruct", typeof(ConstructedNoTypeCheckOrBoxTarget), typeof(ConstructedNoTypeCheckNoBoxStruct))] +[assembly: KeptAttributeAttribute(typeof(TypeMapAttribute), "TrimTargetIsTarget", typeof(TargetAndTrimTarget), typeof(TargetAndTrimTarget))] +[assembly: KeptAttributeAttribute(typeof(TypeMapAttribute), "TrimTargetIsUnrelated", typeof(TargetType), typeof(TrimTarget))] +[assembly: KeptAttributeAttribute(typeof(TypeMapAttribute), nameof(AllocatedNoTypeCheckClassTarget), typeof(AllocatedNoTypeCheckClassTarget), typeof(AllocatedNoTypeCheckClass))] +[assembly: KeptAttributeAttribute(typeof(TypeMapAttribute), nameof(AlloctedNoTypeCheckStructTarget), typeof(AlloctedNoTypeCheckStructTarget), typeof(AllocatedNoTypeCheckStruct))] +[assembly: KeptAttributeAttribute(typeof(TypeMapAttribute), "TypeMapEntryOnly", typeof(TypeMapEntryOnly))] +[assembly: KeptAttributeAttribute(typeof(TypeMapAttribute), nameof(UnboxedOnlyTarget), typeof(UnboxedOnlyTarget), typeof(UnboxedOnly))] +[assembly: KeptAttributeAttribute(typeof(TypeMapAttribute), "TypedRefSource", typeof(MakeRefTargetType), typeof(MakeRef))] +[assembly: KeptAttributeAttribute(typeof(TypeMapAttribute), "TypedRefTarget", typeof(RefValueTargetType), typeof(RefValue))] +[assembly: KeptAttributeAttribute(typeof(TypeMapAttribute), "Constrained", typeof(ConstrainedTarget), typeof(Constrained))] +[assembly: KeptAttributeAttribute(typeof(TypeMapAttribute), "ConstrainedStatic", typeof(ConstraintedStaticTarget), typeof(ConstrainedStatic))] +[assembly: KeptAttributeAttribute(typeof(TypeMapAttribute), "Ldobj", typeof(LdobjTarget), typeof(LdobjType))] +[assembly: KeptAttributeAttribute(typeof(TypeMapAttribute), "ArrayElement", typeof(ArrayElementTarget), typeof(ArrayElement))] +[assembly: KeptAttributeAttribute(typeof(TypeMapAttribute), "TrimTargetIsAllocatedNoTypeCheckNoBoxStruct", typeof(ConstructedNoTypeCheckOrBoxTarget), typeof(ConstructedNoTypeCheckNoBoxStruct))] // The TypeMap Universes are kept separate such that Proxy attributes shouldn't be kept if only the External type map is needed. [assembly: TypeMap("UsedOnlyForExternalTypeMap", typeof(UsedExternalTarget), typeof(UsedTrimTarget))] // Kept +[assembly: KeptAttributeAttribute(typeof(TypeMapAttribute), "UsedOnlyForExternalTypeMap", typeof(UsedExternalTarget), typeof(UsedTrimTarget))] [assembly: TypeMapAssociation(typeof(UsedProxySource), typeof(UsedProxyTarget))] // Removed // The TypeMap Universes are kept separate such that External attributes shouldn't be kept if only the Proxy type map is needed. [assembly: TypeMap("UsedOnlyForExternalTypeMap", typeof(UsedExternalTarget2), typeof(UsedTrimTarget2))] // Removed [assembly: TypeMapAssociation(typeof(UsedProxySource2), typeof(UsedProxyTarget2))] // Kept +[assembly: KeptAttributeAttribute(typeof(TypeMapAssociationAttribute), typeof(UsedProxySource2), typeof(UsedProxyTarget2))] [assembly: TypeMapAssociation(typeof(SourceClass), typeof(ProxyType))] [assembly: TypeMapAssociation(typeof(TypeCheckOnlyClass), typeof(TypeCheckOnlyProxy))] @@ -48,6 +58,10 @@ [assembly: TypeMapAssociation(typeof(I), typeof(IImpl))] [assembly: TypeMapAssociation(typeof(IInterfaceWithDynamicImpl), typeof(IDynamicImpl))] [assembly: TypeMapAssociation(typeof(ArrayElement), typeof(ArrayElementProxy))] +[assembly: KeptAttributeAttribute(typeof(TypeMapAssociationAttribute), typeof(SourceClass), typeof(ProxyType))] +[assembly: KeptAttributeAttribute(typeof(TypeMapAssociationAttribute), typeof(AllocatedNoBoxStructType), typeof(AllocatedNoBoxProxy))] +[assembly: KeptAttributeAttribute(typeof(TypeMapAssociationAttribute), typeof(IInterfaceWithDynamicImpl), typeof(IDynamicImpl))] +[assembly: KeptAttributeAttribute(typeof(TypeMapAssociationAttribute), typeof(ArrayElement), typeof(ArrayElementProxy))] [assembly: TypeMap("UnusedName", typeof(UnusedTargetType), typeof(TrimTarget))] [assembly: TypeMapAssociation(typeof(UnusedSourceClass), typeof(UnusedProxyType))] @@ -55,6 +69,7 @@ [assembly: TypeMap("ClassWithStaticMethodAndField", typeof(TargetType5), typeof(ClassWithStaticMethodAndField))] [assembly: TypeMap("UnimportantString", typeof(PreservedTargetType))] +[assembly: KeptAttributeAttribute(typeof(TypeMapAttribute), "UnimportantString", typeof(PreservedTargetType))] [assembly: KeptAttributeAttribute(typeof(TypeMapAssemblyTargetAttribute))] [assembly: TypeMapAssemblyTarget("library")] diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/TestFramework/VerifyKeptAttributeAttributeWorks.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/TestFramework/VerifyKeptAttributeAttributeWorks.cs new file mode 100644 index 00000000000000..d8e33a8ec62acc --- /dev/null +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/TestFramework/VerifyKeptAttributeAttributeWorks.cs @@ -0,0 +1,310 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.TestFramework; + +[assembly: VerifyKeptAttributeAttributeWorks.NoArguments] +[assembly: KeptAttributeAttribute(typeof(VerifyKeptAttributeAttributeWorks.NoArgumentsAttribute))] + +[assembly: VerifyKeptAttributeAttributeWorks.NoArgumentsWithDuplicates] +[assembly: VerifyKeptAttributeAttributeWorks.NoArgumentsWithDuplicates] +// Roslyn will dedupe so only need one assert +[assembly: KeptAttributeAttribute(typeof(VerifyKeptAttributeAttributeWorks.NoArgumentsWithDuplicatesAttribute))] + +[assembly: VerifyKeptAttributeAttributeWorks.WithArgumentsLooseAssert("arg1", 1, "arg3", typeof(int))] +[assembly: KeptAttributeAttribute(typeof(VerifyKeptAttributeAttributeWorks.WithArgumentsLooseAssertAttribute))] + +[assembly: VerifyKeptAttributeAttributeWorks.WithArgumentsExplicitAssert("arg1", 1, "arg3", typeof(int))] +[assembly: KeptAttributeAttribute(typeof(VerifyKeptAttributeAttributeWorks.WithArgumentsExplicitAssertAttribute), "arg1", 1, "arg3", typeof(int))] + +[assembly: VerifyKeptAttributeAttributeWorks.WithArgumentsWithDuplicatesExplicitAssert("inst1-arg1", 1, "inst1-arg3", typeof(int))] +[assembly: VerifyKeptAttributeAttributeWorks.WithArgumentsWithDuplicatesExplicitAssert("inst2-arg1", 2, "inst2-arg3", typeof(string))] +[assembly: VerifyKeptAttributeAttributeWorks.WithArgumentsWithDuplicatesExplicitAssert("inst3-arg1", 3, "inst3-arg3", typeof(VerifyKeptAttributeAttributeWorks.Foo))] +// Intentionally make kept attribute ordering different than the usages to verify we don't require ordering of kept attributes to match the usages +[assembly: KeptAttributeAttribute(typeof(VerifyKeptAttributeAttributeWorks.WithArgumentsWithDuplicatesExplicitAssertAttribute), "inst1-arg1", 1, "inst1-arg3", typeof(int))] +[assembly: KeptAttributeAttribute(typeof(VerifyKeptAttributeAttributeWorks.WithArgumentsWithDuplicatesExplicitAssertAttribute), "inst3-arg1", 3, "inst3-arg3", typeof(VerifyKeptAttributeAttributeWorks.Foo))] +[assembly: KeptAttributeAttribute(typeof(VerifyKeptAttributeAttributeWorks.WithArgumentsWithDuplicatesExplicitAssertAttribute), "inst2-arg1", 2, "inst2-arg3", typeof(string))] + +[assembly: VerifyKeptAttributeAttributeWorks.WithArgumentsWithGenericWithDuplicatesExplicitAssert("inst1-arg1", 1, "inst1-arg3", typeof(int))] +[assembly: VerifyKeptAttributeAttributeWorks.WithArgumentsWithGenericWithDuplicatesExplicitAssert("inst2-arg1", 2, "inst2-arg3", typeof(string))] +[assembly: VerifyKeptAttributeAttributeWorks.WithArgumentsWithGenericWithDuplicatesExplicitAssert("inst3-arg1", 3, "inst3-arg3", typeof(VerifyKeptAttributeAttributeWorks.Foo))] +// Intentionally make kept attribute ordering different than the usages to verify we don't require ordering of kept attributes to match the usages +[assembly: KeptAttributeAttribute(typeof(VerifyKeptAttributeAttributeWorks.WithArgumentsWithGenericWithDuplicatesExplicitAssertAttribute), "inst1-arg1", 1, "inst1-arg3", typeof(int))] +[assembly: KeptAttributeAttribute(typeof(VerifyKeptAttributeAttributeWorks.WithArgumentsWithGenericWithDuplicatesExplicitAssertAttribute), "inst3-arg1", 3, "inst3-arg3", typeof(VerifyKeptAttributeAttributeWorks.Foo))] +[assembly: KeptAttributeAttribute(typeof(VerifyKeptAttributeAttributeWorks.WithArgumentsWithGenericWithDuplicatesExplicitAssertAttribute), "inst2-arg1", 2, "inst2-arg3", typeof(string))] + +namespace Mono.Linker.Tests.Cases.TestFramework; + +public class VerifyKeptAttributeAttributeWorks +{ + public static void Main() + { + var f = new Foo(); + f.Method(); + f.Field = 1; + f.Property = 1; + f.Event += delegate(object sender, EventArgs e) + { + }; + } + + [Kept] + [KeptMember(".ctor()")] + + [NoArguments] + [KeptAttributeAttribute(typeof(NoArgumentsAttribute))] + + [NoArgumentsWithDuplicates] + [NoArgumentsWithDuplicates] + [KeptAttributeAttribute(typeof(NoArgumentsWithDuplicatesAttribute))] + [KeptAttributeAttribute(typeof(NoArgumentsWithDuplicatesAttribute))] + + [WithArgumentsLooseAssert("arg1", 1, "arg3", typeof(int))] + [KeptAttributeAttribute(typeof(WithArgumentsLooseAssertAttribute))] + + [WithArgumentsExplicitAssert("arg1", 1, "arg3", typeof(int))] + [KeptAttributeAttribute(typeof(WithArgumentsExplicitAssertAttribute), "arg1", 1, "arg3", typeof(int))] + + [WithArgumentsWithDuplicatesLooseAssert("arg1", 1, "arg3", typeof(int))] + [WithArgumentsWithDuplicatesLooseAssert("arg1", 1, "arg3", typeof(int))] + [WithArgumentsWithDuplicatesLooseAssert("arg1", 2, "arg3", typeof(int))] + [KeptAttributeAttribute(typeof(WithArgumentsWithDuplicatesLooseAssertAttribute))] + [KeptAttributeAttribute(typeof(WithArgumentsWithDuplicatesLooseAssertAttribute))] + [KeptAttributeAttribute(typeof(WithArgumentsWithDuplicatesLooseAssertAttribute))] + + [WithArgumentsWithDuplicatesExplicitAssert("inst1-arg1", 1, "inst1-arg3", typeof(int))] + [WithArgumentsWithDuplicatesExplicitAssert("inst2-arg1", 2, "inst2-arg3", typeof(string))] + [WithArgumentsWithDuplicatesExplicitAssert("inst3-arg1", 3, "inst3-arg3", typeof(Foo))] + [WithArgumentsWithDuplicatesExplicitAssert(null, 4, null, null)] + // Intentionally make kept attribute ordering different than the usages to verify we don't require ordering of kept attributes to match the usages + [KeptAttributeAttribute(typeof(WithArgumentsWithDuplicatesExplicitAssertAttribute), "inst1-arg1", 1, "inst1-arg3", typeof(int))] + [KeptAttributeAttribute(typeof(WithArgumentsWithDuplicatesExplicitAssertAttribute), "inst3-arg1", 3, "inst3-arg3", typeof(Foo))] + [KeptAttributeAttribute(typeof(WithArgumentsWithDuplicatesExplicitAssertAttribute), "inst2-arg1", 2, "inst2-arg3", typeof(string))] + [KeptAttributeAttribute(typeof(WithArgumentsWithDuplicatesExplicitAssertAttribute), null, 4, null, null)] + + [WithArgumentsWithGenericWithDuplicatesExplicitAssert("inst1-arg1", 1, "inst1-arg3", typeof(int))] + [WithArgumentsWithGenericWithDuplicatesExplicitAssert("inst2-arg1", 2, "inst2-arg3", typeof(string))] + [WithArgumentsWithGenericWithDuplicatesExplicitAssert("inst3-arg1", 3, "inst3-arg3", typeof(Foo))] + // Intentionally make kept attribute ordering different than the usages to verify we don't require ordering of kept attributes to match the usages + [KeptAttributeAttribute(typeof(WithArgumentsWithGenericWithDuplicatesExplicitAssertAttribute), "inst1-arg1", 1, "inst1-arg3", typeof(int))] + [KeptAttributeAttribute(typeof(WithArgumentsWithGenericWithDuplicatesExplicitAssertAttribute), "inst3-arg1", 3, "inst3-arg3", typeof(Foo))] + [KeptAttributeAttribute(typeof(WithArgumentsWithGenericWithDuplicatesExplicitAssertAttribute), "inst2-arg1", 2, "inst2-arg3", typeof(string))] + public class Foo + { + [Kept] + + [NoArguments] + [KeptAttributeAttribute(typeof(NoArgumentsAttribute))] + + [NoArgumentsWithDuplicates] + [NoArgumentsWithDuplicates] + [KeptAttributeAttribute(typeof(NoArgumentsWithDuplicatesAttribute))] + [KeptAttributeAttribute(typeof(NoArgumentsWithDuplicatesAttribute))] + + [WithArgumentsLooseAssert("arg1", 1, "arg3", typeof(int))] + [KeptAttributeAttribute(typeof(WithArgumentsLooseAssertAttribute))] + + [WithArgumentsExplicitAssert("arg1", 1, "arg3", typeof(int))] + [KeptAttributeAttribute(typeof(WithArgumentsExplicitAssertAttribute), "arg1", 1, "arg3", typeof(int))] + + [WithArgumentsWithDuplicatesLooseAssert("arg1", 1, "arg3", typeof(int))] + [WithArgumentsWithDuplicatesLooseAssert("arg1", 1, "arg3", typeof(int))] + [WithArgumentsWithDuplicatesLooseAssert("arg1", 2, "arg3", typeof(int))] + [KeptAttributeAttribute(typeof(WithArgumentsWithDuplicatesLooseAssertAttribute))] + [KeptAttributeAttribute(typeof(WithArgumentsWithDuplicatesLooseAssertAttribute))] + [KeptAttributeAttribute(typeof(WithArgumentsWithDuplicatesLooseAssertAttribute))] + + [WithArgumentsWithDuplicatesExplicitAssert("inst1-arg1", 1, "inst1-arg3", typeof(int))] + [WithArgumentsWithDuplicatesExplicitAssert("inst2-arg1", 2, "inst2-arg3", typeof(string))] + [WithArgumentsWithDuplicatesExplicitAssert("inst3-arg1", 3, "inst3-arg3", typeof(Foo))] + // Intentionally make kept attribute ordering different than the usages to verify we don't require ordering of kept attributes to match the usages + [KeptAttributeAttribute(typeof(WithArgumentsWithDuplicatesExplicitAssertAttribute), "inst1-arg1", 1, "inst1-arg3", typeof(int))] + [KeptAttributeAttribute(typeof(WithArgumentsWithDuplicatesExplicitAssertAttribute), "inst3-arg1", 3, "inst3-arg3", typeof(Foo))] + [KeptAttributeAttribute(typeof(WithArgumentsWithDuplicatesExplicitAssertAttribute), "inst2-arg1", 2, "inst2-arg3", typeof(string))] + public int Field; + + [Kept] + + [NoArguments] + [KeptAttributeAttribute(typeof(NoArgumentsAttribute))] + + [NoArgumentsWithDuplicates] + [NoArgumentsWithDuplicates] + [KeptAttributeAttribute(typeof(NoArgumentsWithDuplicatesAttribute))] + [KeptAttributeAttribute(typeof(NoArgumentsWithDuplicatesAttribute))] + + [WithArgumentsLooseAssert("arg1", 1, "arg3", typeof(int))] + [KeptAttributeAttribute(typeof(WithArgumentsLooseAssertAttribute))] + + [WithArgumentsExplicitAssert("arg1", 1, "arg3", typeof(int))] + [KeptAttributeAttribute(typeof(WithArgumentsExplicitAssertAttribute), "arg1", 1, "arg3", typeof(int))] + + [WithArgumentsWithDuplicatesLooseAssert("arg1", 1, "arg3", typeof(int))] + [WithArgumentsWithDuplicatesLooseAssert("arg1", 1, "arg3", typeof(int))] + [WithArgumentsWithDuplicatesLooseAssert("arg1", 2, "arg3", typeof(int))] + [KeptAttributeAttribute(typeof(WithArgumentsWithDuplicatesLooseAssertAttribute))] + [KeptAttributeAttribute(typeof(WithArgumentsWithDuplicatesLooseAssertAttribute))] + [KeptAttributeAttribute(typeof(WithArgumentsWithDuplicatesLooseAssertAttribute))] + + [WithArgumentsWithDuplicatesExplicitAssert("inst1-arg1", 1, "inst1-arg3", typeof(int))] + [WithArgumentsWithDuplicatesExplicitAssert("inst2-arg1", 2, "inst2-arg3", typeof(string))] + [WithArgumentsWithDuplicatesExplicitAssert("inst3-arg1", 3, "inst3-arg3", typeof(Foo))] + // Intentionally make kept attribute ordering different than the usages to verify we don't require ordering of kept attributes to match the usages + [KeptAttributeAttribute(typeof(WithArgumentsWithDuplicatesExplicitAssertAttribute), "inst1-arg1", 1, "inst1-arg3", typeof(int))] + [KeptAttributeAttribute(typeof(WithArgumentsWithDuplicatesExplicitAssertAttribute), "inst3-arg1", 3, "inst3-arg3", typeof(Foo))] + [KeptAttributeAttribute(typeof(WithArgumentsWithDuplicatesExplicitAssertAttribute), "inst2-arg1", 2, "inst2-arg3", typeof(string))] + public void Method() + { + } + + [Kept] + + [NoArguments] + [KeptAttributeAttribute(typeof(NoArgumentsAttribute))] + + [NoArgumentsWithDuplicates] + [NoArgumentsWithDuplicates] + [KeptAttributeAttribute(typeof(NoArgumentsWithDuplicatesAttribute))] + [KeptAttributeAttribute(typeof(NoArgumentsWithDuplicatesAttribute))] + + [WithArgumentsLooseAssert("arg1", 1, "arg3", typeof(int))] + [KeptAttributeAttribute(typeof(WithArgumentsLooseAssertAttribute))] + + [WithArgumentsExplicitAssert("arg1", 1, "arg3", typeof(int))] + [KeptAttributeAttribute(typeof(WithArgumentsExplicitAssertAttribute), "arg1", 1, "arg3", typeof(int))] + + [WithArgumentsWithDuplicatesLooseAssert("arg1", 1, "arg3", typeof(int))] + [WithArgumentsWithDuplicatesLooseAssert("arg1", 1, "arg3", typeof(int))] + [WithArgumentsWithDuplicatesLooseAssert("arg1", 2, "arg3", typeof(int))] + [KeptAttributeAttribute(typeof(WithArgumentsWithDuplicatesLooseAssertAttribute))] + [KeptAttributeAttribute(typeof(WithArgumentsWithDuplicatesLooseAssertAttribute))] + [KeptAttributeAttribute(typeof(WithArgumentsWithDuplicatesLooseAssertAttribute))] + + [WithArgumentsWithDuplicatesExplicitAssert("inst1-arg1", 1, "inst1-arg3", typeof(int))] + [WithArgumentsWithDuplicatesExplicitAssert("inst2-arg1", 2, "inst2-arg3", typeof(string))] + [WithArgumentsWithDuplicatesExplicitAssert("inst3-arg1", 3, "inst3-arg3", typeof(Foo))] + // Intentionally make kept attribute ordering different than the usages to verify we don't require ordering of kept attributes to match the usages + [KeptAttributeAttribute(typeof(WithArgumentsWithDuplicatesExplicitAssertAttribute), "inst1-arg1", 1, "inst1-arg3", typeof(int))] + [KeptAttributeAttribute(typeof(WithArgumentsWithDuplicatesExplicitAssertAttribute), "inst3-arg1", 3, "inst3-arg3", typeof(Foo))] + [KeptAttributeAttribute(typeof(WithArgumentsWithDuplicatesExplicitAssertAttribute), "inst2-arg1", 2, "inst2-arg3", typeof(string))] + public int Property; + + [Kept] + [KeptBackingField] + [KeptEventAddMethod] + [KeptEventRemoveMethod] + + [NoArguments] + [KeptAttributeAttribute(typeof(NoArgumentsAttribute))] + + [NoArgumentsWithDuplicates] + [NoArgumentsWithDuplicates] + [KeptAttributeAttribute(typeof(NoArgumentsWithDuplicatesAttribute))] + [KeptAttributeAttribute(typeof(NoArgumentsWithDuplicatesAttribute))] + + [WithArgumentsLooseAssert("arg1", 1, "arg3", typeof(int))] + [KeptAttributeAttribute(typeof(WithArgumentsLooseAssertAttribute))] + + [WithArgumentsExplicitAssert("arg1", 1, "arg3", typeof(int))] + [KeptAttributeAttribute(typeof(WithArgumentsExplicitAssertAttribute), "arg1", 1, "arg3", typeof(int))] + + [WithArgumentsWithDuplicatesLooseAssert("arg1", 1, "arg3", typeof(int))] + [WithArgumentsWithDuplicatesLooseAssert("arg1", 1, "arg3", typeof(int))] + [WithArgumentsWithDuplicatesLooseAssert("arg1", 2, "arg3", typeof(int))] + [KeptAttributeAttribute(typeof(WithArgumentsWithDuplicatesLooseAssertAttribute))] + [KeptAttributeAttribute(typeof(WithArgumentsWithDuplicatesLooseAssertAttribute))] + [KeptAttributeAttribute(typeof(WithArgumentsWithDuplicatesLooseAssertAttribute))] + + [WithArgumentsWithDuplicatesExplicitAssert("inst1-arg1", 1, "inst1-arg3", typeof(int))] + [WithArgumentsWithDuplicatesExplicitAssert("inst2-arg1", 2, "inst2-arg3", typeof(string))] + [WithArgumentsWithDuplicatesExplicitAssert("inst3-arg1", 3, "inst3-arg3", typeof(Foo))] + // Intentionally make kept attribute ordering different than the usages to verify we don't require ordering of kept attributes to match the usages + [KeptAttributeAttribute(typeof(WithArgumentsWithDuplicatesExplicitAssertAttribute), "inst1-arg1", 1, "inst1-arg3", typeof(int))] + [KeptAttributeAttribute(typeof(WithArgumentsWithDuplicatesExplicitAssertAttribute), "inst3-arg1", 3, "inst3-arg3", typeof(Foo))] + [KeptAttributeAttribute(typeof(WithArgumentsWithDuplicatesExplicitAssertAttribute), "inst2-arg1", 2, "inst2-arg3", typeof(string))] + public event EventHandler Event; + } + + [Kept] + [KeptMember(".ctor()")] + [KeptBaseType(typeof(Attribute))] + [KeptAttributeAttribute(typeof(AttributeUsageAttribute))] + [AttributeUsage(AttributeTargets.All)] + public class NoArgumentsAttribute : Attribute + { + } + + [Kept] + [KeptBaseType(typeof(Attribute))] + [KeptAttributeAttribute(typeof(AttributeUsageAttribute))] + [AttributeUsage(AttributeTargets.All)] + public class WithArgumentsLooseAssertAttribute : Attribute + { + [Kept] + public WithArgumentsLooseAssertAttribute(object arg1, int arg2, string arg3, Type arg4) + { + } + } + + [Kept] + [KeptBaseType(typeof(Attribute))] + [KeptAttributeAttribute(typeof(AttributeUsageAttribute))] + [AttributeUsage(AttributeTargets.All)] + public class WithArgumentsExplicitAssertAttribute : Attribute + { + [Kept] + public WithArgumentsExplicitAssertAttribute(object arg1, int arg2, string arg3, Type arg4) + { + } + } + + [Kept] + [KeptMember(".ctor()")] + [KeptBaseType(typeof(Attribute))] + [KeptAttributeAttribute(typeof(AttributeUsageAttribute))] + [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] + public class NoArgumentsWithDuplicatesAttribute : Attribute + { + } + + [Kept] + [KeptMember(".ctor()")] + [KeptBaseType(typeof(Attribute))] + [KeptAttributeAttribute(typeof(AttributeUsageAttribute))] + [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] + public class WithArgumentsWithDuplicatesLooseAssertAttribute : Attribute + { + [Kept] + public WithArgumentsWithDuplicatesLooseAssertAttribute(object arg1, int arg2, string arg3, Type arg4) + { + } + } + + [Kept] + [KeptMember(".ctor()")] + [KeptBaseType(typeof(Attribute))] + [KeptAttributeAttribute(typeof(AttributeUsageAttribute))] + [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] + public class WithArgumentsWithDuplicatesExplicitAssertAttribute : Attribute + { + [Kept] + public WithArgumentsWithDuplicatesExplicitAssertAttribute(object arg1, int arg2, string arg3, Type arg4) + { + } + } + + [Kept] + [KeptMember(".ctor()")] + [KeptBaseType(typeof(Attribute))] + [KeptAttributeAttribute(typeof(AttributeUsageAttribute))] + [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] + public class WithArgumentsWithGenericWithDuplicatesExplicitAssertAttribute : Attribute + { + [Kept] + public WithArgumentsWithGenericWithDuplicatesExplicitAssertAttribute(object arg1, int arg2, string arg3, Type arg4) + { + } + } +} diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/TestFramework/VerifyLocalsAreChanged.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/TestFramework/VerifyLocalsAreChanged.cs new file mode 100644 index 00000000000000..e2737e15bbd82a --- /dev/null +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/TestFramework/VerifyLocalsAreChanged.cs @@ -0,0 +1,44 @@ +using System; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Metadata; + +namespace Mono.Linker.Tests.Cases.TestFramework +{ + [SetupLinkerSubstitutionFile("VerifyLocalsAreChanged.xml")] + public class VerifyLocalsAreChanged + { + public static void Main() + { + TestMethod_1(); + + TestMethod_2(); + } + + [Kept] + struct NestedType + { + public NestedType(int arg) + { + throw new NotImplementedException(); + } + } + + [Kept] + [ExpectBodyModified] + [ExpectLocalsModified] + static NestedType TestMethod_1() + { + var value = new NestedType(42); + return value; + } + + [Kept] + [ExpectedLocalsSequence(["Mono.Linker.Tests.Cases.TestFramework.VerifyLocalsAreChanged/NestedType"])] + [ExpectBodyModified] + static NestedType TestMethod_2() + { + var value = new NestedType(2); + return value; + } + } +} diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/TestFramework/VerifyLocalsAreChanged.xml b/src/tools/illink/test/Mono.Linker.Tests.Cases/TestFramework/VerifyLocalsAreChanged.xml new file mode 100644 index 00000000000000..aa7f20ee18b917 --- /dev/null +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/TestFramework/VerifyLocalsAreChanged.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/tools/illink/test/Mono.Linker.Tests/TestCasesRunner/AssemblyChecker.cs b/src/tools/illink/test/Mono.Linker.Tests/TestCasesRunner/AssemblyChecker.cs index 05f0c47812be1b..28efa01c1d88a0 100644 --- a/src/tools/illink/test/Mono.Linker.Tests/TestCasesRunner/AssemblyChecker.cs +++ b/src/tools/illink/test/Mono.Linker.Tests/TestCasesRunner/AssemblyChecker.cs @@ -126,13 +126,13 @@ protected virtual IEnumerable VerifyModule(ModuleDefinition original, Mo var expected = original.Assembly.MainModule.AllDefinedTypes() .SelectMany(t => GetCustomAttributeCtorValues(t, nameof(KeptModuleReferenceAttribute))) - .ToHashSet(); + .ToArray(); var actual = linked.ModuleReferences .Select(name => name.Name) - .ToHashSet(); + .ToArray(); - if (!expected.SetEquals(actual)) + if (!expected.SequenceEqual(actual)) yield return $"In module {original.FileName} Expected module references `{string.Join(", ", expected)}` but got `{string.Join(", ", actual)}`"; foreach (var err in VerifyCustomAttributes(original, linked)) @@ -832,7 +832,7 @@ public static IEnumerable VerifyBodyProperties(MethodDefinition src, Met if (src.CustomAttributes.Any(attr => attr.AttributeType.Name == expectModifiedAttributeName)) { - if (linkedValues.ToHashSet().SetEquals(srcValues.ToHashSet())) + if (linkedValues.SequenceEqual(srcValues)) { yield return $"Expected method `{src} to have it's {propertyDescription} modified, however, the {propertyDescription} were the same as the original\n{FormattingUtils.FormatSequenceCompareFailureMessage(linkedValues, srcValues)}"; } @@ -840,14 +840,14 @@ public static IEnumerable VerifyBodyProperties(MethodDefinition src, Met else if (expectedSequenceAttribute != null) { var expected = getExpectFromSequenceAttribute(expectedSequenceAttribute).ToArray(); - if (!linkedValues.ToHashSet().SetEquals(expected.ToHashSet())) + if (!linkedValues.SequenceEqual(expected)) { yield return $"Expected method `{src} to have it's {propertyDescription} modified, however, the sequence of {propertyDescription} does not match the expected value\n{FormattingUtils.FormatSequenceCompareFailureMessage2(linkedValues, expected, srcValues)}"; } } else { - if (!linkedValues.ToHashSet().SetEquals(srcValues.ToHashSet())) + if (!linkedValues.SequenceEqual(srcValues)) { yield return $"Expected method `{src} to have it's {propertyDescription} unchanged, however, the {propertyDescription} differ from the original\n{FormattingUtils.FormatSequenceCompareFailureMessage(linkedValues, srcValues)}"; } @@ -859,7 +859,7 @@ IEnumerable VerifyReferences(AssemblyDefinition original, AssemblyDefini var expected = original.MainModule.AllDefinedTypes() .SelectMany(t => GetCustomAttributeCtorValues(t, nameof(KeptReferenceAttribute))) .Select(ReduceAssemblyFileNameOrNameToNameOnly) - .ToHashSet(); + .ToArray(); /* - The test case will always need to have at least 1 reference. @@ -870,14 +870,14 @@ IEnumerable VerifyReferences(AssemblyDefinition original, AssemblyDefini Once 1 kept reference attribute is used, the test will need to define all of of it's expected references */ - if (expected.Count == 0) + if (expected.Length == 0) yield break; var actual = linked.MainModule.AssemblyReferences .Select(name => name.Name) - .ToHashSet(); + .ToArray(); - if (!expected.SetEquals(actual)) + if (!expected.SequenceEqual(actual)) yield return $"Expected references `{string.Join(", ", expected)}` do not match actual references `{string.Join(", ", actual)}`"; } @@ -918,7 +918,7 @@ IEnumerable VerifyExportedTypes(AssemblyDefinition original, AssemblyDef var expectedTypes = original.MainModule.AllDefinedTypes() .SelectMany(t => GetCustomAttributeCtorValues(t, nameof(KeptExportedTypeAttribute)).Select(l => l.FullName)); - if (!linked.MainModule.ExportedTypes.Select(l => l.FullName).ToHashSet().SetEquals(expectedTypes.ToHashSet())) + if (!linked.MainModule.ExportedTypes.Select(l => l.FullName).SequenceEqual(expectedTypes)) yield return $"Exported types do not match expected."; } @@ -961,33 +961,54 @@ protected virtual IEnumerable VerifyPseudoAttributes(EventDefinition src protected virtual IEnumerable VerifyCustomAttributes(ICustomAttributeProvider src, ICustomAttributeProvider linked) { - var expectedAttrs = GetExpectedAttributes(src).ToHashSet(); - var linkedAttrs = FilterLinkedAttributes(linked).ToHashSet(); - if (!linkedAttrs.SetEquals(expectedAttrs)) + var expectedAttrs = GetExpectedAttributes(src).ToArray(); + var linkedAttrs = FilterLinkedAttributes(linked).ToList(); + + var missingExpected = new List(); + foreach (var attr in expectedAttrs) { - var missing = $"Missing: {string.Join(", ", expectedAttrs.Except(linkedAttrs))}"; - var extra = $"Extra: {string.Join(", ", linkedAttrs.Except(expectedAttrs))}"; - string name = src switch + var match = linkedAttrs.FirstOrDefault(l => + { + if (l.TypeFullName != attr.TypeFullName) + return false; + + if (attr.CheckParameters) + return attr.ParameterValues.SequenceEqual(l.ParameterValues); + + return true; + }); + if (match != null) + linkedAttrs.Remove(match); + else + missingExpected.Add(attr); + } + + if (missingExpected.Count > 0) + yield return $"Missing custom attributes on `{GetNameForSource()}`:\n{string.Join(Environment.NewLine, missingExpected.Select(a => $" {a}").ToArray())}"; + + if (linkedAttrs.Count > 0) + yield return $"Extra custom attributes on `{GetNameForSource()}`:\n{string.Join(Environment.NewLine, linkedAttrs.Select(a => $" {a}").ToArray())}"; + + string GetNameForSource() + { + return src switch { MethodReturnType m => $"return type of '{m.Method}'", ParameterDefinition p => $"parameter '{p}' of method {p.Method}", GenericParameter g => $"generic parameter '{g}' of {g.Owner}", _ => src.ToString() }; - - yield return string.Join(Environment.NewLine, $"Custom attributes on `{name}` are not matching:", missing, extra); } } protected virtual IEnumerable VerifySecurityAttributes(ICustomAttributeProvider src, ISecurityDeclarationProvider linked) { var expectedAttrs = GetCustomAttributeCtorValues(src, nameof(KeptSecurityAttribute)) - .Select(attr => attr.ToString()) - .ToHashSet(); + .Select(attr => attr.ToString()).ToArray(); - var linkedAttrs = FilterLinkedSecurityAttributes(linked).ToHashSet(); + var linkedAttrs = FilterLinkedSecurityAttributes(linked).ToArray(); - if (!linkedAttrs.SetEquals(expectedAttrs)) + if (!linkedAttrs.SequenceEqual(expectedAttrs)) { var missing = $"Missing: {string.Join(", ", expectedAttrs.Except(linkedAttrs))}"; var extra = $"Extra: {string.Join(", ", linkedAttrs.Except(expectedAttrs))}"; @@ -1116,10 +1137,28 @@ static bool IsLdtokenOnPrivateImplementationDetails(TypeDefinition privateImplem return false; } - protected static IEnumerable GetExpectedAttributes(ICustomAttributeProvider original) + protected static IEnumerable GetExpectedAttributes(ICustomAttributeProvider original) { - foreach (var expectedAttrs in GetCustomAttributeCtorValues(original, nameof(KeptAttributeAttribute))) - yield return expectedAttrs.ToString(); + foreach (var expectedAttrs in original.CustomAttributes.Where(w => w.AttributeType.Name == nameof(KeptAttributeAttribute))) + { + if (expectedAttrs.Constructor.Parameters.Count == 1) + yield return new ExpectedAttributeComparisonInfo(false, (expectedAttrs.ConstructorArguments[0].Value as object).ToString(), Array.Empty()); + else if (expectedAttrs.Constructor.Parameters.Count == 2) + { + var expectedParameters = ((CustomAttributeArgument[])expectedAttrs.ConstructorArguments[1].Value).Select(a => + { + var arg = (CustomAttributeArgument)a.Value; + if (arg.Value == null) + return "null"; + return arg.Value.ToString(); + }).ToArray(); + yield return new ExpectedAttributeComparisonInfo(true, (expectedAttrs.ConstructorArguments[0].Value as object).ToString(), expectedParameters); + } + else + { + throw new ArgumentException($"Unhandled {nameof(KeptAttributeAttribute)} constructor with {expectedAttrs.Constructor.Parameters.Count} parameters."); + } + } // The name of the generated fixed buffer type is a little tricky. // Some versions of csc name it `e__FixedBuffer0` @@ -1132,7 +1171,7 @@ protected static IEnumerable GetExpectedAttributes(ICustomAttributeProvi Assert.Fail($"Could not locate original fixed field for {srcDefinition}"); foreach (var additionalExpectedAttributesFromFixedField in GetCustomAttributeCtorValues(fixedField, nameof(KeptAttributeOnFixedBufferTypeAttribute))) - yield return additionalExpectedAttributesFromFixedField.ToString(); + yield return new ExpectedAttributeComparisonInfo(false, additionalExpectedAttributesFromFixedField.ToString(), Array.Empty()); } } @@ -1141,7 +1180,7 @@ protected static IEnumerable GetExpectedAttributes(ICustomAttributeProvi /// /// /// - protected virtual IEnumerable FilterLinkedAttributes(ICustomAttributeProvider linked) + protected virtual IEnumerable FilterLinkedAttributes(ICustomAttributeProvider linked) { foreach (var attr in linked.CustomAttributes) { @@ -1173,7 +1212,9 @@ protected virtual IEnumerable FilterLinkedAttributes(ICustomAttributePro break; } - yield return attr.AttributeType.FullName; + yield return new ActualAttributeComparisonInfo( + attr.AttributeType.FullName, + GetCustomAttributeConstructorArgumentValues(attr).Select(p => p == null ? "null" : p.ToString()).ToArray()); } } @@ -1327,17 +1368,17 @@ IEnumerable VerifyGenericParameterConstraints(GenericParameter src, Gene // C# doesn't have syntax for annotating generic parameter constraints with arbitrary attributes, // so expected attributes on generic parameter constraints are specified on the generic parameter itself. - HashSet<(string ConstraintType, string AttributeType)> expectedConstraintAttributes = src.CustomAttributes + (string ConstraintType, string AttributeType)[] expectedConstraintAttributes = src.CustomAttributes .Where(a => IsKeptAttributeOnConstraint(a)) .Select(a => (a.ConstructorArguments[0].Value.ToString(), a.ConstructorArguments[1].Value.ToString())) - .ToHashSet(); + .ToArray(); - HashSet<(string ConstraintType, string AttributeType)> linkedConstraintAttributes = linked.Constraints + (string ConstraintType, string AttributeType)[] linkedConstraintAttributes = linked.Constraints .Where(c => c.HasCustomAttributes) .SelectMany(c => c.CustomAttributes.Select(a => (c.ConstraintType.FullName, a.AttributeType.FullName))) - .ToHashSet(); + .ToArray(); - if (!expectedConstraintAttributes.SetEquals(linkedConstraintAttributes)) + if (!expectedConstraintAttributes.SequenceEqual(linkedConstraintAttributes)) { var missing = $"Missing: {string.Join(", ", expectedConstraintAttributes.Except(linkedConstraintAttributes).Select(c => $"{c.AttributeType} on {c.ConstraintType}"))}"; var extra = $"Extra: {string.Join(", ", linkedConstraintAttributes.Except(expectedConstraintAttributes).Select(c => $"{c.AttributeType} on {c.ConstraintType}"))}"; @@ -1492,5 +1533,66 @@ protected static IEnumerable GetStringArrayAttributeValue(CustomAttribut { return ((CustomAttributeArgument[])attribute.ConstructorArguments[0].Value)?.Select(arg => arg.Value.ToString()); } + + protected static IEnumerable GetCustomAttributeConstructorArgumentValues(CustomAttribute attribute) + { + foreach (var argument in attribute.ConstructorArguments) + { + if (argument.Value is CustomAttributeArgument nestedArgument) + yield return nestedArgument.Value; + else + yield return argument.Value; + } + } + + protected class ExpectedAttributeComparisonInfo + { + public readonly bool CheckParameters; + public readonly string TypeFullName; + public readonly string[] ParameterValues; + + public ExpectedAttributeComparisonInfo(bool checkParameters, string typeFullName, string[] parameterValues) + { + if (string.IsNullOrEmpty(typeFullName)) + throw new ArgumentNullException(nameof(typeFullName)); + if (parameterValues == null) + throw new ArgumentNullException(nameof(parameterValues)); + CheckParameters = checkParameters; + TypeFullName = typeFullName; + ParameterValues = parameterValues; + } + + public override string ToString() + { + if (ParameterValues.Length == 0) + return TypeFullName; + + return $"{TypeFullName}({string.Join(",", ParameterValues)})"; + } + } + + protected class ActualAttributeComparisonInfo + { + public readonly string TypeFullName; + public readonly string[] ParameterValues; + + public ActualAttributeComparisonInfo(string typeFullName, string[] parameterValues) + { + if (string.IsNullOrEmpty(typeFullName)) + throw new ArgumentNullException(nameof(typeFullName)); + if (parameterValues == null) + throw new ArgumentNullException(nameof(parameterValues)); + TypeFullName = typeFullName; + ParameterValues = parameterValues; + } + + public override string ToString() + { + if (ParameterValues.Length == 0) + return TypeFullName; + + return $"{TypeFullName}({string.Join(",", ParameterValues)})"; + } + } } }